import { env } from "@haushaltsApp/env/server";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { registerRoutes } from "./routes";
import { shoppingWsHandlers } from "./ws/shopping-ws";
import { db, eq } from "@haushaltsApp/db";
import { session as sessionTable } from "@haushaltsApp/db/schema";

const app = new Hono();

app.use(logger());
app.use(
  "/*",
  cors({
    origin: env.CORS_ORIGIN,
    allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allowHeaders: ["Content-Type", "Authorization", "x-household-id"],
    credentials: true,
  }),
);

registerRoutes(app);

// When running under Bun directly (not imported as a module for tests),
// start Bun.serve with WebSocket support.
if (typeof Bun !== "undefined" && !process.env.BUN_TEST) {
  Bun.serve({
    port: Number(process.env.PORT ?? 3000),
    hostname: "0.0.0.0",
    websocket: shoppingWsHandlers,
    async fetch(req: Request, server) {
      const url = new URL(req.url);
      if (url.pathname === "/api/shopping-lists/ws") {
        const token = url.searchParams.get("token") ?? "";
        const householdId = url.searchParams.get("householdId") ?? "";

        if (!householdId) {
          return new Response("Missing householdId", { status: 400 });
        }

        const rawToken = token.includes(".") ? token.split(".")[0] : token;
        if (!rawToken) return new Response("Unauthorized", { status: 401 });

        const sessionRow = await db.query.session.findFirst({
          where: eq(sessionTable.token, rawToken),
          with: { user: true },
        });

        if (!sessionRow?.user || sessionRow.expiresAt < new Date()) {
          return new Response("Unauthorized", { status: 401 });
        }

        const upgraded = server.upgrade(req, {
          data: { householdId, userId: sessionRow.user.id },
        });
        if (upgraded) return undefined as unknown as Response;
        return new Response("WebSocket upgrade failed", { status: 400 });
      }

      return app.fetch(req);
    },
  });
}

export default app;
