/**
 * SolidStart server middleware (runs on every request).
 *
 * Workaround for a Vinxi 0.5.7 + @solidjs/start 1.3.2 build issue where
 * file-based API routes in `src/routes/api/*` are registered in the page
 * router tree but never mounted as Nitro handlers, so every `/api/*`
 * request returns a 404 from the SolidStart page renderer.
 *
 * This middleware intercepts `/api/*` paths at the SolidStart middleware
 * layer (which IS in the request pipeline) and proxies them to the Rust
 * gateway.
 *
 * Responsibilities:
 *   - /api/gateway/*path  → proxy to Rust gateway
 *   - /api/kb/categories  → proxy to Rust gateway
 *   - /api/kb/articles    → proxy to Rust gateway
 *   - /api/kb/articles/:slug → proxy to Rust gateway
 *
 * Uses the @solidjs/start `createMiddleware` pattern, which Vinxi/h3 will
 * actually invoke via the `onRequest` hook.
 */

import { createMiddleware } from "@solidjs/start/middleware";

const GATEWAY_URL = (
  process.env.GATEWAY_URL || "http://localhost:9100"
).replace(/\/+$/, "");

const PUBLIC_API_URL = (
  process.env.PUBLIC_API_URL ||
  process.env.NEXT_PUBLIC_API_URL ||
  `${GATEWAY_URL}/api`
).replace(/\/+$/, "");

function buildUpstream(path: string, query: string = ""): string {
  // PUBLIC_API_URL ends with /api; path starts with /api/...
  // Strip the /api prefix from path so we don't double up.
  if (PUBLIC_API_URL.endsWith("/api")) {
    const stripped = path.replace(/^\/api/, "");
    return `${PUBLIC_API_URL}${stripped}${query}`;
  }
  return `${PUBLIC_API_URL}${path}${query}`;
}

async function proxyToGateway(fetchEvent: any, upstreamPath: string) {
  const req = fetchEvent.request;
  const method = req.method.toUpperCase();
  const url = new URL(req.url);
  const queryString = url.search || "";

  // Read body for methods that have one
  let body: BodyInit | undefined;
  if (["POST", "PUT", "PATCH", "DELETE"].includes(method)) {
    try {
      body = await req.clone().text();
    } catch {
      body = undefined;
    }
  }

  // Forward auth + content-type + cookie
  const headers: Record<string, string> = {
    "Content-Type":
      req.headers.get("content-type") || "application/json",
  };
  const auth = req.headers.get("authorization");
  if (auth) headers["Authorization"] = auth;
  const cookie = req.headers.get("cookie");
  if (cookie) headers["Cookie"] = cookie;

  const upstream = buildUpstream(upstreamPath, queryString);

  let response: Response;
  try {
    response = await fetch(upstream, {
      method,
      headers,
      body,
      cache: "no-store",
    });
  } catch (err: any) {
    return new Response(
      JSON.stringify({
        success: false,
        error: `Gateway unreachable: ${err?.message || "unknown"}`,
      }),
      {
        status: 502,
        headers: { "Content-Type": "application/json" },
      },
    );
  }

  // Copy response headers (skip hop-by-hop), ensure Content-Type
  const respHeaders = new Headers();
  response.headers.forEach((value, key) => {
    const k = key.toLowerCase();
    if (k === "server" || k === "transfer-encoding" || k === "connection") return;
    respHeaders.set(key, value);
  });
  if (!respHeaders.get("content-type")) {
    respHeaders.set("Content-Type", "application/json");
  }

  const respBody = await response.text();
  return new Response(respBody, {
    status: response.status,
    statusText: response.statusText,
    headers: respHeaders,
  });
}

async function handlePayuReturn(fetchEvent: any): Promise<Response> {
  const req = fetchEvent.request;
  const url = new URL(req.url);
  const isFailure = url.pathname.endsWith("/payu-return-failure");

  let formBody: URLSearchParams;
  try {
    const text = await req.text();
    formBody = new URLSearchParams(text);
  } catch {
    formBody = new URLSearchParams();
  }

  const txnid =
    formBody.get("txnid") || url.searchParams.get("txnid") || "";
  const status =
    formBody.get("status") ||
    (isFailure ? "failure" : url.searchParams.get("status") || "failure");
  const mihpayid = formBody.get("mihpayid") || "";
  const hash = formBody.get("hash") || "";
  const amount = formBody.get("amount") || "";
  const productinfo = formBody.get("productinfo") || "";
  const firstname = formBody.get("firstname") || "";
  const email = formBody.get("email") || "";
  const phone = formBody.get("phone") || "";
  const udf1 = formBody.get("udf1") || "";
  const udf2 = formBody.get("udf2") || "";
  const udf3 = formBody.get("udf3") || "";
  const udf4 = formBody.get("udf4") || "";
  const udf5 = formBody.get("udf5") || "";

  const query = new URLSearchParams();
  query.set("txnid", txnid);
  query.set("status", status);
  if (mihpayid) query.set("mihpayid", mihpayid);
  if (hash) query.set("hash", hash);
  if (amount) query.set("amount", amount);
  if (productinfo) query.set("productinfo", productinfo);
  if (firstname) query.set("firstname", firstname);
  if (email) query.set("email", email);
  if (phone) query.set("phone", phone);
  if (udf1) query.set("udf1", udf1);
  if (udf2) query.set("udf2", udf2);
  if (udf3) query.set("udf3", udf3);
  if (udf4) query.set("udf4", udf4);
  if (udf5) query.set("udf5", udf5);

  const target = `/dashboard/wallet/payu-return?${query.toString()}`;
  return new Response(null, {
    status: 302,
    headers: { Location: target },
  });
}

export default createMiddleware({
  onRequest: async (fetchEvent) => {
    const url = new URL(fetchEvent.request.url);
    const path = url.pathname;

    // Only handle /api/* paths
    if (!path.startsWith("/api/")) return;

    // Gateway proxy catch-all: /api/gateway/* → strip /api/gateway, send rest
    if (path === "/api/gateway" || path.startsWith("/api/gateway/")) {
      const subPath = path.slice("/api/gateway".length) || "/";
      // Normalize to /api/... contract for the Rust gateway
      const normalized =
        subPath.startsWith("/api/") || subPath === "/api"
          ? subPath
          : `/api${subPath}`;
      return proxyToGateway(fetchEvent, normalized);
    }

    // Knowledge base routes
    if (path === "/api/kb/categories") {
      return proxyToGateway(fetchEvent, "/api/kb/categories");
    }
    if (path === "/api/kb/articles") {
      return proxyToGateway(fetchEvent, "/api/kb/articles");
    }
    if (path.startsWith("/api/kb/articles/")) {
      return proxyToGateway(fetchEvent, path);
    }

    // PayU form POST return handler. PayU submits an HTML form to either the
    // success or failure URL with all transaction data in the request body.
    // We read the form fields, forward them to the verify endpoint, and
    // redirect the user to the SPA payu-return page with a query string.
    if (path === "/api/payments/payu-return") {
      return handlePayuReturn(fetchEvent);
    }

    // All other /api/* paths — proxy to the gateway
    return proxyToGateway(fetchEvent, path);
  },
});
