import type { CreateExpressContextOptions } from "@trpc/server/adapters/express";
import type { User } from "../../drizzle/schema";
import { users } from "../../drizzle/schema";
import { getDb } from "../db";
import { eq } from "drizzle-orm";
import jwt from "jsonwebtoken";
import { COOKIE_NAME } from "@shared/const";
import crypto from "crypto";

export type TrpcContext = {
  req: CreateExpressContextOptions["req"];
  res: CreateExpressContextOptions["res"];
  user: User | null;
};

export async function createContext(
  opts: CreateExpressContextOptions
): Promise<TrpcContext> {
  // Init user var to null to avoid ReferenceError
  let user: User | null = null;
  // console.log("🔍 [Context] Initializing context...");

  // Attempt to recover user from JWT cookie
  try {
    const cookieHeader = opts.req.headers.cookie;
    if (cookieHeader) {
      const cookies = Object.fromEntries(
        cookieHeader.split('; ').map(c => c.split('='))
      );
      const token = cookies[COOKIE_NAME];

      if (token) {
        const decoded = jwt.verify(token, process.env.JWT_SECRET || "s3cret-leifo-key-change-me") as { userId: number; role: "admin" | "user" };
        if (decoded && decoded.userId) {
          // We can fetch the full user from DB if needed, but for roles this is enough to start
          // Ideally we should fetch the user to ensure they still exist/aren't banned
          // For strict type safety with the User type:
          const db = await getDb();
          if (db) {
            const [foundUser] = await db.select().from(users).where(eq(users.id, decoded.userId));
            if (foundUser) {
              user = foundUser;
            }
          }
        }
      }
    }

    // Check for API Key if not authenticated via cookie
    if (!user) {
      const apiKey = opts.req.headers['x-api-key'];
      if (typeof apiKey === 'string') {
        const db = await getDb();
        if (db) {
          const apiKeyHash = crypto.createHash("sha256").update(apiKey).digest("hex");
          const [foundUser] = await db.select().from(users).where(eq(users.apiKeyHash, apiKeyHash));
          if (foundUser) {
            user = foundUser;
          }
        }
      }
    }
  } catch (err) {
    // Invalid token, treat as guest
    user = null;
  }

  return {
    req: opts.req,
    res: opts.res,
    user,
  };
}
