// app/api/access/route.ts
export const dynamic = "force-dynamic";
import { NextResponse } from "next/server";
import { cookies, headers } from "next/headers";
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@supabase/supabase-js";
import { sendAccessUpdatedEmail, sendInvitationWithActivationEmail } from "@/lib/emailMigrationHelpers";
import { getUserPermissions, canManageUsers } from "@/lib/permissions";
// import type { Database } from "@/types/supabase"; // Temporairement commenté

type OrgRow = { id: string; name?: string; structure_api?: string | null };
type MemberRow = { role: string; revoked: boolean };

function makeServerClient() {
  return createRouteHandlerClient({ cookies });
}

/**
 * Fonction simplifiée pour résoudre l'ID d'organisation
 * Compatible avec la nouvelle approche utilisant /api/me et les headers injectés par api()
 */
async function resolveOrgId(sb: ReturnType<typeof makeServerClient>): Promise<string | null> {
  const h = headers();
  const c = cookies();

  // PRIORITÉ 1: Déterminer si l'utilisateur est staff ou non
  try {
    const { data: { user } } = await sb.auth.getUser();
    if (!user) {
      console.log("❌ Aucun utilisateur authentifié");
      return null;
    }

    const { data: staffData } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();
    const isStaff = !!staffData?.is_staff;
    
    console.log("👤 Utilisateur:", { id: user.id, email: user.email, isStaff });

    if (!isStaff) {
      // UTILISATEUR CLIENT: Utiliser get_my_org (source de vérité)
      try {
        const { data: myOrgRaw } = await sb.rpc("get_my_org").maybeSingle();
        const myOrg = (myOrgRaw as OrgRow | null) ?? null;
        if (myOrg?.id) {
          console.log("✅ Org client via get_my_org:", { id: myOrg.id, name: myOrg.name });
          return myOrg.id;
        }
      } catch (e: unknown) {
        const message = e instanceof Error ? e.message : String(e);
        console.warn("⚠️ Erreur get_my_org:", message);
      }
      
      console.log("❌ Aucune organisation trouvée pour le client");
      return null;
    }

    // UTILISATEUR STAFF: Utiliser cookies/headers
    console.log("👨‍💼 Utilisateur staff - résolution via cookies/headers");

  } catch (e: any) {
    console.warn("⚠️ Erreur détection utilisateur:", e.message);
    return null;
  }

  // --- CODE STAFF (conservé tel quel) ---
  // 0.a) ID direct
  const serverCookieOrgId = c.get("active_org_id")?.value;
  if (serverCookieOrgId) {
    console.log("🔍 Org ID via cookie httpOnly active_org_id:", serverCookieOrgId);
    return serverCookieOrgId;
  }

  // 0.b) Clé/API (structure_api) - ex: active_org_key
  const activeOrgKey = c.get("active_org_key")?.value;
  if (activeOrgKey) {
    console.log("🔍 Recherche org via active_org_key (structure_api):", activeOrgKey);
    const { data } = await sb.from("organizations").select("id").eq("structure_api", activeOrgKey).maybeSingle();
    const org = (data as OrgRow | null) ?? null;
    if (org?.id) {
      console.log("✅ Org ID trouvé via active_org_key:", org.id);
      return org.id;
    }
  }

  // 0.c) Nom encodé en base64 - ex: active_org_name_b64
  const nameB64 = c.get("active_org_name_b64")?.value;
  if (nameB64) {
    try {
      const decoded = Buffer.from(nameB64, "base64").toString("utf8");
      console.log("🔍 Recherche org via active_org_name_b64 décodé:", decoded);
      const { data } = await sb.from("organizations").select("id").eq("name", decoded).maybeSingle();
      const org = (data as OrgRow | null) ?? null;
      if (org?.id) {
        console.log("✅ Org ID trouvé via active_org_name_b64:", org.id);
        return org.id;
      }
    } catch (e) {
      console.warn("⚠️ Erreur décodage active_org_name_b64:", e);
    }
  }

  // --- 1) Headers injectés par le helper client (compat héritage) ---
  const fromHeader = h.get("x-active-org-id");
  if (fromHeader) {
    console.log("🔍 Org ID via header x-active-org-id:", fromHeader);
    return fromHeader;
  }

  // --- 2) Cookies hérités (compat) ---
  const legacyCookieId = c.get("active_org_id")?.value;
  if (legacyCookieId) {
    console.log("🔍 Org ID via cookie legacy active_org_id:", legacyCookieId);
    return legacyCookieId;
  }

  // --- 3) Nom d'entreprise via headers (compat) ---
  let name = h.get("x-company-name") || "";
  if (!name) {
    const b64 = h.get("x-company-name-b64");
    if (b64) {
      try {
        name = Buffer.from(b64, "base64").toString("utf8");
        console.log("🔍 Nom d'entreprise décodé depuis header base64:", name);
      } catch (e) {
        console.warn("⚠️ Erreur décodage header x-company-name-b64:", e);
      }
    }
  }

  if (name) {
    console.log("🔍 Recherche org via nom (headers):", name);
    const { data } = await sb.from("organizations").select("id").eq("name", name).maybeSingle();
    const org = (data as OrgRow | null) ?? null;
    if (org?.id) {
      console.log("✅ Org ID trouvé via nom (headers):", org.id);
      return org.id;
    }
  }

  console.log("❌ Aucune organisation trouvée pour le staff");
  return null;
}

async function guardRole(sb: ReturnType<typeof makeServerClient>, org_id: string) {
  const { data: { user } } = await sb.auth.getUser();
  if (!user) {
    console.log("❌ Pas d'utilisateur authentifié");
    return { ok: false as const, status: 401 as const };
  }

  // Vérifier d'abord si c'est un staff
  const { data: staffData } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();

  if (staffData?.is_staff) {
    console.log("✅ Utilisateur staff autorisé");
    return { ok: true as const, status: 200 as const, user };
  }

  // Si pas staff, vérifier les permissions d'organisation
  const { data: meRow, error } = await sb
    .from("organization_members")
    .select("role, revoked")
    .eq("org_id", org_id)
    .eq("user_id", user.id)
    .maybeSingle();
  const me = (meRow as MemberRow | null) ?? null;

  if (error) {
    console.log("❌ Erreur lors de la vérification du rôle:", error);
    return { ok: false as const, status: 403 as const };
  }
  
  if (!me) {
    console.log("❌ Utilisateur non membre de l'organisation");
    return { ok: false as const, status: 403 as const };
  }
  
  if (me.revoked) {
    console.log("❌ Utilisateur révoqué");
    return { ok: false as const, status: 403 as const };
  }
  
  if (!["ADMIN", "SUPER_ADMIN"].includes(me.role)) {
    console.log("❌ Rôle insuffisant:", me.role);
    return { ok: false as const, status: 403 as const };
  }

  console.log("✅ Utilisateur autorisé avec rôle:", me.role);
  return { ok: true as const, status: 200 as const, user };
}

export async function GET() {
  console.log("📥 GET /api/access - Début du traitement");
  
  const sb = makeServerClient();
  const org_id = await resolveOrgId(sb);

  // If no org_id resolved, only allow staff users to proceed (null-org semantics).
  // Non-staff callers must have an active org.
  let staffMode = false;
  if (!org_id) {
    // detect staff status
    const { data: { user } } = await sb.auth.getUser();
    if (!user) {
      console.log("❌ Aucun utilisateur authentifié");
      return new NextResponse("Unauthorized", { status: 401 });
    }
    try {
      const { data: staffData } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();
      staffMode = !!staffData?.is_staff;
    } catch (e) {
      staffMode = false;
    }

    if (!staffMode) {
      console.log("❌ Aucune organisation active trouvée (non-staff)");
      return json(400, { error: "no_active_org", message: "Aucune organisation active trouvée" });
    }
    console.log("👨‍💼 Staff mode: no active org selected — proceeding with global access");
  }

  console.log("🏢 Organisation active:", org_id);

  // For non-staff flows, validate role on the resolved org
  if (!staffMode) {
    const g = await guardRole(sb, org_id as string);
    if (!g.ok) {
      console.log("❌ Accès refusé");
      return new NextResponse("Forbidden", { status: g.status });
    }
    
    // Vérification des permissions: AGENT et COMPTA ne peuvent pas gérer les utilisateurs
    const permissions = await getUserPermissions(sb);
    if (!permissions) {
      console.log("❌ Permission refusée: utilisateur non authentifié");
      return new NextResponse("Unauthorized", { status: 401 });
    }
    
    if (!canManageUsers(permissions)) {
      console.log("❌ Permission refusée: gestion des utilisateurs non autorisée pour", permissions.role);
      return new NextResponse("Forbidden - Accès réservé aux administrateurs", { status: 403 });
    }
  }

  console.log("✅ Accès autorisé, récupération des membres...");

  // Récupération directe des membres de l'organisation
  let data: any[] = [];
  
  try {
    console.log("🔍 Récupération des membres via requête directe...");
    
    // Requête directe pour récupérer les membres avec leurs informations utilisateur
    // If staffMode (global), don't filter by org_id and include org_id in the result.
    let membersQuery = sb.from("organization_members").select(
      staffMode
        ? `
        org_id,
        user_id,
        role,
        revoked,
        created_at,
        revoked_at
      `
        : `
        user_id,
        role,
        revoked,
        created_at,
        revoked_at
      `
    );

    if (!staffMode) {
      membersQuery = membersQuery.eq("org_id", org_id as string);
    }

    const { data: members, error } = await membersQuery.order("created_at", { ascending: false });

    if (error) {
      console.log("❌ Erreur récupération members:", error);
      return json(500, { error: "database_error", message: error.message });
    }

    if (!members || members.length === 0) {
      console.log("⚠️ Aucun membre trouvé pour cette organisation");
      return json(200, { items: [] });
    }

    // Récupérer les informations utilisateur pour chaque membre
  const userIds = members.map((m: any) => m.user_id).filter(Boolean);
    
    // Utiliser le service role pour récupérer les infos utilisateur
    const admin = createClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.SUPABASE_SERVICE_ROLE_KEY!,
      { auth: { autoRefreshToken: false, persistSession: false } }
    );

    // Récupérer les utilisateurs par batch
    const usersData: any[] = [];
    for (const userId of userIds) {
      try {
        const { data: userData } = await admin.auth.admin.getUserById(userId);
        if (userData?.user) {
          usersData.push({
            id: userData.user.id,
            email: userData.user.email,
            first_name: userData.user.user_metadata?.first_name || userData.user.user_metadata?.display_name?.split(' ')[0] || null,
            last_sign_in_at: userData.user.last_sign_in_at || null
          });
        }
      } catch (e) {
        console.warn("⚠️ Erreur récupération user", userId, ":", e);
      }
    }

    // Combiner les données
    data = members.map((member: any) => {
      const user = usersData.find(u => u.id === member.user_id);
      return {
        org_id: member.org_id || null,
        user_id: member.user_id,
        first_name: user?.first_name || null,
        email: user?.email || "Email non disponible",
        role: member.role,
        created_at: member.created_at,
        revoked: member.revoked,
        revoked_at: member.revoked_at,
        last_sign_in_at: user?.last_sign_in_at || null
      };
    });

    console.log("✅ Membres récupérés avec succès:", data.length);
  } catch (e: any) {
    console.log("❌ Erreur inattendue:", e.message);
    return json(500, { error: "server_error", message: e.message });
  }
  
  console.log("📤 Retour des données:", { count: data.length });
  return json(200, { items: data });
}

export async function POST(req: Request) {
  console.log("📥 POST /api/access - Création d'un nouveau membre");
  
  const sb = makeServerClient();
  // Parse body early so we can reuse it for org resolution
  const body = await req.json().catch(() => ({} as any));

  let org_id = await resolveOrgId(sb) || (body?.org_id || null);

  // If no org_id resolved, only allow staff callers to proceed and try staff fallbacks.
  let staffMode = false;
  if (!org_id) {
    const { data: { user } } = await sb.auth.getUser();
    if (!user) {
      console.log("❌ Aucun utilisateur authentifié");
      return new NextResponse("Unauthorized", { status: 401 });
    }
    try {
      const { data: staffData } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();
      staffMode = !!staffData?.is_staff;
    } catch (e) {
      staffMode = false;
    }

    // If staff, try staff_settings.active_org_id as a fallback
    if (staffMode && !org_id) {
      try {
        const { data: ss } = await sb.from('staff_settings').select('active_org_id').eq('user_id', user.id).maybeSingle();
        if (ss?.active_org_id) org_id = ss.active_org_id;
      } catch {}
    }

    if (!org_id && !staffMode) {
      console.log("❌ Aucune organisation active trouvée (non-staff)");
      return json(400, { error: "no_active_org", message: "Aucune organisation active trouvée" });
    }
  }

  // For non-staff flows, validate role on the resolved org
  if (!staffMode) {
    const g = await guardRole(sb, org_id as string);
    if (!g.ok) {
      console.log("❌ Accès refusé");
      return new NextResponse("Forbidden", { status: g.status });
    }
  }

  // body was parsed above
  const email = String(body.email || "").trim().toLowerCase();
  const role = (body.role || "AGENT").toString().toUpperCase(); // ADMIN | SUPER_ADMIN | AGENT | COMPTA
  const first_name = String(body.first_name || "").trim();

  console.log("📝 Données reçues:", { email, role, first_name, org_id });

  if (!email) {
    console.log("❌ Email manquant");
    return json(400, { error: "missing_email", message: "L'email est requis" });
  }
  
  if (role === "SUPER_ADMIN") {
    console.log("❌ Tentative de création SUPER_ADMIN");
    return json(403, { error: "forbidden_role", message: "Le rôle SUPER_ADMIN ne peut être assigné" });
  }

  // Service role pour les opérations administratives
  const admin = createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!,
    { auth: { autoRefreshToken: false, persistSession: false } }
  );

  try {
    // 1) Trouver l'utilisateur existant par email
    console.log("🔍 Recherche utilisateur par email...");
    const { data: existingUser, error: findUserErr } = await admin
      .rpc("find_user_by_email", { email_param: email })
      .maybeSingle();

    const existing = (existingUser as { id: string } | null) ?? null;
    let user_id: string | undefined = existing?.id;

    if (!user_id) {
      console.log("👤 Utilisateur non trouvé, création directe du compte vérifié...");

      const origin = process.env.NEXT_PUBLIC_BASE_URL || "https://paie.odentas.fr";
      const signinUrl = `${origin}/signin`;

      const { data: orgData } = await admin
        .from('organizations')
        .select('name')
        .eq('id', org_id)
        .maybeSingle();
      const orgName = (orgData as any)?.name || '';

      const metadata = {
        first_name: first_name || null,
        role,
        org_id,
        org_name: orgName,
      };

      const { data: createData, error: createError } = await admin.auth.admin.createUser({
        email,
        email_confirm: true,
        user_metadata: metadata,
      });

      if (createError || !createData?.user?.id) {
        console.log("❌ Erreur création utilisateur:", createError?.message);
        return json(400, { error: createError?.message || "create_failed" });
      }

      const newUserId = createData.user.id;

      // Attacher à l'organisation
      const { error: memberError } = await admin
        .from("organization_members")
        .upsert({ org_id, user_id: newUserId, role, revoked: false }, { onConflict: "org_id,user_id" });
        
      if (memberError) {
        console.log("❌ Erreur création membership:", memberError.message);
        return json(400, { error: memberError.message });
      }
      
      // Configurer les préférences d'auth
      await admin
        .from("user_auth_prefs")
        .upsert({ user_id: newUserId, allow_magic_link: true, allow_password: false });
      
      // Envoyer l'email de confirmation
      try {
        await sendInvitationWithActivationEmail(email, {
          firstName: first_name || undefined,
          organizationName: orgName,
          activationUrl: signinUrl,
          role,
        });
      } catch (emailErr) {
        console.warn('⚠️ Envoi email confirmation échoué (non-bloquant):', (emailErr as any)?.message || emailErr);
      }
      
      console.log("✅ Compte créé et email envoyé avec succès");
      return json(200, { ok: true, message: "Compte créé" });
    } else {
      console.log("👤 Utilisateur existant trouvé, ajout/mise à jour membership...");
      // 2) Upsert membership si user déjà existant
      //    → Détecter un éventuel changement de rôle pour notifier l'utilisateur

      // Lire l'ancien rôle si membership existant
      let oldRole: string | null = null;
      try {
        const { data: existingMember } = await admin
          .from("organization_members")
          .select("role")
          .eq("org_id", org_id)
          .eq("user_id", user_id)
          .maybeSingle();
        oldRole = (existingMember as any)?.role || null;
      } catch {}

      const { error } = await admin
        .from("organization_members")
        .upsert({ org_id, user_id, role, revoked: false }, { onConflict: "org_id,user_id" });
        
      if (error) {
        console.log("❌ Erreur upsert membership:", error.message);
        return json(400, { error: error.message });
      }
      
      console.log("✅ Membership créé/mis à jour avec succès");

      // Si le rôle a changé, envoyer l'email de modification d'habilitation
      try {
        if (oldRole && oldRole !== role) {
          const { data: userData } = await admin.auth.admin.getUserById(user_id);
          const to = userData?.user?.email;
          const firstName = userData?.user?.user_metadata?.first_name || undefined;
          const { data: orgRow } = await admin.from('organizations').select('name').eq('id', org_id).maybeSingle();

          // Acteur (modifié par)
          const sb = makeServerClient();
          const { data: { user: actor } } = await sb.auth.getUser();
          const updatedBy = actor?.email || 'Administrateur';

          if (to) {
            await sendAccessUpdatedEmail(to, {
              firstName: firstName || undefined,
              organizationName: String((orgRow as any)?.name || ''),
              oldRole,
              newRole: role,
              updatedBy,
              updateDate: new Date().toLocaleString('fr-FR'),
              ctaUrl: `${process.env.NEXT_PUBLIC_BASE_URL || 'https://paie.odentas.fr'}/vos-acces`,
            });
          }
        }
      } catch (e) {
        console.warn('⚠️ Envoi email habilitation échoué (non-bloquant):', (e as any)?.message || e);
      }
      return json(200, { ok: true, message: "Utilisateur ajouté à l'organisation" });
    }
  } catch (e: any) {
    console.log("❌ Erreur inattendue:", e.message);
    return json(500, { error: "server_error", message: e.message });
  }
}

function json(status: number, body: any) {
  return NextResponse.json(body, { status });
}
