import { eq } from "drizzle-orm";
import type { NextFunction, Request, Response } from "express";
import { auth } from "../auth/auth.js";
import { db } from "../db/db.js";
import { type UserRole, userRoles } from "../db/schema/user_roles.js";

declare global {
	namespace Express {
		interface Request {
			user?: {
				id: string;
				email?: string;
				roles: Record<string, string[]>;
				username?: string | null;
			};
		}
	}
}
function toWebHeaders(nodeHeaders: Request["headers"]): Headers {
	const h = new Headers();
	for (const [key, value] of Object.entries(nodeHeaders)) {
		if (Array.isArray(value)) {
			value.forEach((v) => h.append(key, v));
		} else if (value !== undefined) {
			h.set(key, value);
		}
	}
	return h;
}

export const requireAuth = (moduleName?: string, requiredRoles?: string[]) => {
	return async (req: Request, res: Response, next: NextFunction) => {
		try {
			const headers = toWebHeaders(req.headers);

			// Get session
			const session = await auth.api.getSession({
				headers,
				query: { disableCookieCache: true },
			});

			if (!session) {
				return res.status(401).json({ error: "No active session" });
			}

			const userId = session.user.id;

			// Get roles
			const roles = await db
				.select()
				.from(userRoles)
				.where(eq(userRoles.userId, userId));

			// Organize roles by module
			const rolesByModule: Record<string, string[]> = {};
			for (const r of roles) {
				if (!rolesByModule[r.module]) rolesByModule[r.module] = [];
				rolesByModule[r.module].push(r.role);
			}

			req.user = {
				id: userId,
				email: session.user.email,
				roles: rolesByModule,
				username: session.user.username,
			};

			// SystemAdmin override
			const hasSystemAdmin = Object.values(rolesByModule)
				.flat()
				.includes("systemAdmin");

			// Role check (skip if systemAdmin)
			if (requiredRoles?.length && !hasSystemAdmin) {
				const moduleRoles = moduleName
					? (rolesByModule[moduleName] ?? [])
					: Object.values(rolesByModule).flat();
				const hasAccess = moduleRoles.some((role) =>
					requiredRoles.includes(role),
				);
				if (!hasAccess) {
					return res.status(403).json({ error: "Forbidden" });
				}
			}

			next();
		} catch (err) {
			console.error("Auth middleware error:", err);
			res.status(500).json({ error: "Auth check failed" });
		}
	};
};
