// app/api/access/[memberId]/role/route.ts
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 } from "@/lib/emailMigrationHelpers";
import { getUserPermissions, canModifyUser } from "@/lib/permissions";

type MemberRecord = { role: string; revoked: boolean };

async function resolveOrgId(sb: ReturnType<typeof createRouteHandlerClient>): Promise<string | null> {
  const h = headers();
  const c = cookies();

  // 1) Déterminer utilisateur et statut staff
  try {
    const { data: { user } } = await sb.auth.getUser();
    if (!user) return null;

  const { data: staffData } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();
  const isStaff = !!(staffData as any)?.is_staff;

    if (!isStaff) {
      // Client: utiliser get_my_org comme source de vérité
      try {
        const { data: myOrgRaw } = await sb.rpc("get_my_org").maybeSingle();
        const myOrg = (myOrgRaw as { id?: string } | null) ?? null;
        if (myOrg?.id) return myOrg.id;
      } catch {}
    }
  } catch {}

  // 2) Staff et fallbacks génériques
  const serverCookieOrgId = c.get("active_org_id")?.value;
  if (serverCookieOrgId) return serverCookieOrgId;

  const activeOrgKey = c.get("active_org_key")?.value;
  if (activeOrgKey) {
    const { data } = await sb.from("organizations").select("id").eq("structure_api", activeOrgKey).maybeSingle();
    const org = (data as { id?: string } | null) ?? null;
    if (org?.id) return org.id;
  }

  const nameB64 = c.get("active_org_name_b64")?.value;
  if (nameB64) {
    try {
      const decoded = Buffer.from(nameB64, "base64").toString("utf8");
      const { data } = await sb.from("organizations").select("id").eq("name", decoded).maybeSingle();
      const org = (data as { id?: string } | null) ?? null;
      if (org?.id) return org.id;
    } catch {}
  }

  const fromHeader = h.get("x-active-org-id");
  if (fromHeader) return fromHeader;

  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"); } catch {}
    }
  }
  if (name) {
    const { data } = await sb.from("organizations").select("id").eq("name", name).maybeSingle();
    const org = (data as { id?: string } | null) ?? null;
    if (org?.id) return org.id;
  }

  return null;
}

async function guardRole(sb: ReturnType<typeof createRouteHandlerClient>, org_id: string) {
  const { data: { user } } = await sb.auth.getUser();
  if (!user) return false;
  const { data: meRow } = await sb
    .from("organization_members")
    .select("role,revoked")
    .eq("org_id", org_id)
    .eq("user_id", user.id)
    .maybeSingle();
  const me = (meRow as MemberRecord | null) ?? null;
  return !!me && !me.revoked && ["ADMIN", "SUPER_ADMIN"].includes(me.role);
}

export async function PATCH(req: Request, { params }: { params: { memberId: string } }) {
  const sb = createRouteHandlerClient({ cookies });

  // Résoudre org via logique robuste (client/staff)
  let org_id = await resolveOrgId(sb);

  // Si toujours pas trouvé, tenter via le membre ciblé (utile pour staff ou fallback)
  if (!org_id) {
    try {
      const { data: target } = await sb
        .from('organization_members')
        .select('org_id')
        .eq('user_id', params.memberId)
        .is('revoked', false)
        .maybeSingle();
      if ((target as any)?.org_id) org_id = (target as any).org_id as string;
    } catch {}
  }

  // Auth de l'appelant
  const { data: { user } } = await sb.auth.getUser();
  if (!user) return new NextResponse("Unauthorized", { status: 401 });

  if (!org_id) {
    return new NextResponse("no_active_org", { status: 400 });
  }

  // Vérifier les droits sur l'org
  if (!(await guardRole(sb, org_id))) return new NextResponse("Forbidden", { status: 403 });

  const body = await req.json().catch(()=> ({}));
  const role = (body.role || "").toString().toUpperCase();
  if (!role) return NextResponse.json({ error: "missing_role" }, { status: 400 });

  const admin = createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!,
    { auth: { autoRefreshToken: false, persistSession: false } }
  );

  // Lire ancien rôle
  let oldRole: string | null = null;
  try {
    const { data: existingMember } = await admin
      .from('organization_members')
      .select('role')
      .eq('org_id', org_id)
      .eq('user_id', params.memberId)
      .is('revoked', false)
      .maybeSingle();
    oldRole = (existingMember as any)?.role || null;
  } catch {}

  // Vérification des permissions hiérarchiques: empêcher ADMIN de modifier SUPER_ADMIN
  const permissions = await getUserPermissions(sb);
  if (!permissions) {
    return new NextResponse("Unauthorized", { status: 401 });
  }
  
  if (oldRole && !canModifyUser(permissions, oldRole as any)) {
    console.log("❌ Permission refusée: impossible de modifier un utilisateur", oldRole, "avec le rôle", permissions.role);
    return new NextResponse("Forbidden - Vous ne pouvez pas modifier cet utilisateur", { status: 403 });
  }

  const { error } = await admin.from("organization_members")
    .update({ role })
    .eq("org_id", org_id)
    .eq("user_id", params.memberId)
    .is("revoked", false);
  if (error) return NextResponse.json({ error: error.message }, { status: 400 });

  // Email de notification si changement
  try {
    if (oldRole && oldRole !== role) {
      const { data: userData } = await admin.auth.admin.getUserById(params.memberId);
      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();

      const updatedBy = user.email || 'Administrateur';

      if (to) {
        await sendAccessUpdatedEmail(to, {
          firstName,
          organizationName: String((orgRow as any)?.name || ''),
          oldRole,
          newRole: role,
          updatedBy,
          updateDate: new Date().toLocaleString('fr-FR'),
        });
      }
    }
  } catch (e) {
    console.warn('⚠️ Envoi email habilitation échoué (non-bloquant):', (e as any)?.message || e);
  }

  return NextResponse.json({ ok: true });
}