import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);
const WEB_SESSION_COOKIE = "enterprise_pos_session";
const rendererPort = Number(process.env.POS_RENDERER_PORT || process.env.VITE_RENDERER_PORT || 5173);

function parseCookieHeader(rawCookieHeader: string | string[] | undefined) {
  const header = Array.isArray(rawCookieHeader) ? rawCookieHeader.join(";") : rawCookieHeader ?? "";
  return header.split(";").reduce<Record<string, string>>((cookies, part) => {
    const [name, ...valueParts] = part.trim().split("=");
    if (!name || valueParts.length === 0) {
      return cookies;
    }

    try {
      cookies[name] = decodeURIComponent(valueParts.join("="));
    } catch {
      cookies[name] = valueParts.join("=");
    }
    return cookies;
  }, {});
}

function buildSessionCookie(sessionToken: string, rememberMe: boolean, expiresAt: string, secure: boolean) {
  const parts = [
    `${WEB_SESSION_COOKIE}=${encodeURIComponent(sessionToken)}`,
    "Path=/",
    "HttpOnly",
    "SameSite=Lax"
  ];

  if (rememberMe) {
    const expires = new Date(expiresAt);
    if (!Number.isNaN(expires.getTime())) {
      parts.push(`Expires=${expires.toUTCString()}`);
    }
  }

  if (secure) {
    parts.push("Secure");
  }

  return parts.join("; ");
}

function clearSessionCookie(secure: boolean) {
  const parts = [
    `${WEB_SESSION_COOKIE}=`,
    "Path=/",
    "HttpOnly",
    "SameSite=Lax",
    "Max-Age=0",
    "Expires=Thu, 01 Jan 1970 00:00:00 GMT"
  ];

  if (secure) {
    parts.push("Secure");
  }

  return parts.join("; ");
}

function shouldUseSecureCookie(rawForwardedProto: string | string[] | undefined) {
  const forwardedProto = Array.isArray(rawForwardedProto) ? rawForwardedProto[0] : rawForwardedProto;
  return forwardedProto === "https" || process.env.POS_COOKIE_SECURE === "1";
}

function devPosApiPlugin(): Plugin {
  const backendEntry = path.resolve(__dirname, "dist/backend/index.js");

  return {
    name: "dev-pos-api-bridge",
    apply: "serve",
    configureServer(server) {
      server.middlewares.use("/api/pos", async (req, res) => {
        if (!req.url) {
          res.statusCode = 400;
          res.end("Missing request URL");
          return;
        }

        const method = req.url.split("?")[0].replace(/^\/+/, "");
        if (!method) {
          res.statusCode = 404;
          res.end("Missing backend method");
          return;
        }

        const chunks: Buffer[] = [];
        for await (const chunk of req) {
          chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
        }

        const rawBody = Buffer.concat(chunks).toString("utf8");
        let args: unknown[] = [];

        if (rawBody) {
          try {
            const parsed = JSON.parse(rawBody) as { args?: unknown[] };
            args = Array.isArray(parsed.args) ? parsed.args : [];
          } catch {
            res.statusCode = 400;
            res.setHeader("Content-Type", "application/json");
            res.end(JSON.stringify({ message: "Invalid JSON body" }));
            return;
          }
        }

        try {
          if (!fs.existsSync(backendEntry)) {
            res.statusCode = 503;
            res.setHeader("Content-Type", "application/json");
            res.end(
              JSON.stringify({
                message: "Backend bundle is not ready yet. Wait for `npm run dev:backend` to finish its first build."
              })
            );
            return;
          }

          const resolvedEntry = require.resolve(backendEntry);
          delete require.cache[resolvedEntry];
          const mod = require(resolvedEntry) as {
            backend?: Record<string, (...fnArgs: unknown[]) => unknown>;
            runWithRequestContext?: <T>(authToken: string | null, handler: () => Promise<T> | T) => Promise<T>;
          };
          const backend = mod.backend;
          const runWithRequestContext = mod.runWithRequestContext;

          if (!backend || typeof backend[method] !== "function") {
            res.statusCode = 404;
            res.setHeader("Content-Type", "application/json");
            res.end(JSON.stringify({ message: `Backend method not found: ${method}` }));
            return;
          }

          const cookies = parseCookieHeader(req.headers.cookie);
          const authToken = cookies[WEB_SESSION_COOKIE] ?? null;
          const result = runWithRequestContext
            ? await runWithRequestContext(authToken, () => backend[method](...args))
            : await backend[method](...args);

          if (method === "login" && result && typeof result === "object" && "success" in result && (result as { success?: boolean }).success) {
            const payload = result as {
              session?: { expiresAt?: string; rememberMe?: boolean } | null;
              sessionToken?: string | null;
            };
            if (payload.sessionToken) {
              const secure = shouldUseSecureCookie(req.headers["x-forwarded-proto"]);
              const cookie = buildSessionCookie(
                payload.sessionToken,
                Boolean(payload.session?.rememberMe),
                payload.session?.expiresAt ?? new Date(Date.now() + 20 * 60_000).toISOString(),
                secure
              );
              res.setHeader("Set-Cookie", cookie);
            }
          }

          if (method === "logout") {
            const secure = shouldUseSecureCookie(req.headers["x-forwarded-proto"]);
            res.setHeader("Set-Cookie", clearSessionCookie(secure));
          }

          res.statusCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.end(JSON.stringify(result));
        } catch (error) {
          const message = error instanceof Error ? error.message : "Backend bridge error";
          res.statusCode = 500;
          res.setHeader("Content-Type", "application/json");
          res.end(
            JSON.stringify({
              message,
              stack: error instanceof Error ? error.stack : undefined
            })
          );
        }
      });
    }
  };
}

export default defineConfig({
  root: path.resolve(__dirname, "apps/desktop/src/renderer"),
  plugins: [react(), devPosApiPlugin()],
  server: {
    port: Number.isFinite(rendererPort) ? rendererPort : 5173,
    strictPort: true
  },
  build: {
    outDir: path.resolve(__dirname, "dist/renderer"),
    emptyOutDir: true,
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes("apps/desktop/src/renderer/src/features/reports/components/report-detail-page")) {
            return "route-report-detail";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/reports/components/report-ops-pages")) {
            return "route-report-ops";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/reports/components/reports-page")) {
            return "route-report-workspace";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/accounting")) {
            return "feature-accounting";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/settings")) {
            return "feature-settings";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/purchases")) {
            return "feature-purchases";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/inventory")) {
            return "feature-inventory";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/customers") || id.includes("apps/desktop/src/renderer/src/features/suppliers")) {
            return "feature-crm";
          }
          if (id.includes("apps/desktop/src/renderer/src/features/billing")) {
            return "feature-billing";
          }
          if (id.includes("node_modules")) {
            if (id.includes("react") || id.includes("react-dom")) {
              return "vendor-react";
            }
            if (id.includes("@tanstack")) {
              return "vendor-tanstack";
            }
            if (id.includes("ag-grid-enterprise")) {
              return "vendor-grid-enterprise";
            }
            if (id.includes("ag-grid-react")) {
              return "vendor-grid-react";
            }
            if (id.includes("ag-grid-community")) {
              return "vendor-grid-core";
            }
            if (id.includes("xlsx")) {
              return "vendor-xlsx";
            }
            if (id.includes("jspdf-autotable")) {
              return "vendor-pdf-table";
            }
            if (id.includes("jspdf")) {
              return "vendor-pdf";
            }
            if (id.includes("html2canvas")) {
              return "vendor-html-capture";
            }
            if (id.includes("framer-motion") || id.includes("lucide-react")) {
              return "vendor-ui";
            }
          }
        }
      }
    }
  },
  resolve: {
    alias: {
      "@renderer": path.resolve(__dirname, "apps/desktop/src/renderer/src"),
      "@shared": path.resolve(__dirname, "packages/shared/src")
    }
  }
});
