import type { Handle } from "@sveltejs/kit";
import type { User } from "$lib/types";

// Lazy-load auth module to avoid blocking on server startup
let authModule: typeof import("$lib/server/auth") | null = null;
async function getAuthModule() {
  if (!authModule) {
    authModule = await import("$lib/server/auth");
  }
  return authModule;
}

const SESSION_COOKIE_NAME = "neoad_session";
const MULTI_SESSION_COOKIE_NAME = "neoad_multi_session";
const BROWSER_ID_COOKIE_NAME = "neoad_browser_id";

const buildCorsHeaders = (origin: string | null) => {
  const headers = new Headers();
  if (origin) {
    headers.set("Access-Control-Allow-Origin", origin);
    headers.set("Access-Control-Allow-Credentials", "true");
    headers.append("Vary", "Origin");
  } else {
    headers.set("Access-Control-Allow-Origin", "*");
  }
  headers.set(
    "Access-Control-Allow-Headers",
    "Content-Type, Authorization, X-Requested-With"
  );
  headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
  return headers;
};

// Routes publiques (pas besoin d'auth)
const PUBLIC_ROUTES = [
  "/",
  "/login",
  "/register",
  "/forgot-password",
  "/reset-password",
  "/faq",
  "/contact",
  "/mentions-legales",
  "/confidentialite",
  "/cgv",
  "/cookies",
];

// Routes réservées aux admins
const ADMIN_ROUTES = ["/admin"];

export const handle: Handle = async ({ event, resolve }) => {
  const origin = event.request.headers.get("origin");
  if (event.request.method === "OPTIONS") {
    return new Response(null, {
      status: 204,
      headers: buildCorsHeaders(origin)
    });
  }

  // Récupérer les cookies
  const sessionToken = event.cookies.get(SESSION_COOKIE_NAME);
  const browserId = event.cookies.get(BROWSER_ID_COOKIE_NAME);
  
  // Initialiser les locals
  event.locals.user = null;
  event.locals.session = null;
  event.locals.company = null;
  event.locals.multiSessionAccounts = [];
  
  // Gérer la multi-session si browser_id présent
  if (browserId) {
    try {
      const auth = await getAuthModule();
      // Ajouter un timeout pour éviter les blocages
      const multiDataPromise = auth.getMultiSessionData(browserId);
      const timeoutPromise = new Promise((_, reject) => 
        setTimeout(() => reject(new Error('Multi-session timeout')), 5000)
      );
      
      const multiData = await Promise.race([multiDataPromise, timeoutPromise]) as Awaited<ReturnType<typeof getMultiSessionData>>;
      if (multiData) {
        event.locals.multiSessionAccounts = multiData.accounts;
        
        // Utiliser la session active de la multi-session
        const activeSession = multiData.accounts.find(
          acc => acc.session.session_token === multiData.multiSession.active_session_token
        );
        
        if (activeSession) {
          event.locals.user = activeSession.user;
          event.locals.session = activeSession.session;
          event.locals.company = activeSession.company || null;
        }
      }
    } catch (error) {
      console.error("Erreur lors de la récupération de la multi-session:", error);
      // En cas de timeout ou erreur, nettoyer les cookies de multi-session pour permettre une reconnexion propre
      event.cookies.delete(BROWSER_ID_COOKIE_NAME, { path: "/" });
      event.cookies.delete(MULTI_SESSION_COOKIE_NAME, { path: "/" });
    }
  }
  
  // Fallback sur la session classique si pas de multi-session
  if (!event.locals.user && sessionToken) {
    try {
      const auth = await getAuthModule();
      // Ajouter un timeout pour éviter les blocages
      const sessionPromise = auth.getSessionByToken(sessionToken);
      const timeoutPromise = new Promise((_, reject) => 
        setTimeout(() => reject(new Error('Session timeout')), 5000)
      );
      
      const result = await Promise.race([sessionPromise, timeoutPromise]) as Awaited<ReturnType<typeof auth.getSessionByToken>>;
      if (result) {
        event.locals.user = result.user;
        event.locals.session = result.session;
        event.locals.company = result.company || null;
      } else {
        // Session invalide, supprimer le cookie
        event.cookies.delete(SESSION_COOKIE_NAME, { path: "/" });
      }
    } catch (error) {
      console.error("Erreur lors de la vérification de session:", error);
      event.cookies.delete(SESSION_COOKIE_NAME, { path: "/" });
    }
  }
  
  const path = event.url.pathname;
  
  // Rediriger les anciennes routes /broadcaster vers /dashboard (migration vers dashboard unifié)
  if (path === "/broadcaster" || path.startsWith("/broadcaster/")) {
    return new Response(null, {
      status: 302,
      headers: { Location: "/dashboard" },
    });
  }
  
  // Vérifier si la route est publique
  const isPublicRoute = PUBLIC_ROUTES.some(
    (route) => path === route || path.startsWith(`${route}/`)
  );
  
  // Vérifier si c'est une route API
  const isApiRoute = path.startsWith("/api/");
  
  // Vérifier si c'est une route admin
  const isAdminRoute = ADMIN_ROUTES.some(
    (route) => path === route || path.startsWith(`${route}/`)
  );
  
  // Vérifier si c'est une route dashboard (client)
  const isDashboardRoute = path.startsWith("/dashboard") || path.startsWith("/advertiser") || path.startsWith("/agency") || path.startsWith("/broadcaster");
  
  // Protection des routes
  if (!isPublicRoute && !isApiRoute) {
    // Si pas connecté, rediriger vers login
    if (!event.locals.user) {
      const redirectTo = encodeURIComponent(path);
      return new Response(null, {
        status: 302,
        headers: { Location: `/login?redirect=${redirectTo}` },
      });
    }
    
    // Si route admin, vérifier le rôle
    if (isAdminRoute && event.locals.user.role !== "admin") {
      return new Response(null, {
        status: 302,
        headers: { Location: "/dashboard" },
      });
    }
  }
  
  // Si connecté et essaie d'accéder à login/register, rediriger vers dashboard
  if (event.locals.user && (path === "/login" || path === "/register")) {
    const redirectTo = event.locals.user.role === "admin" ? "/admin" : "/dashboard";
    return new Response(null, {
      status: 302,
      headers: { Location: redirectTo },
    });
  }
  
  const response = await resolve(event);
  const corsHeaders = buildCorsHeaders(origin);
  corsHeaders.forEach((value, key) => {
    if (!response.headers.has(key)) {
      response.headers.set(key, value);
    }
  });
  return response;
};
