// app/api/cotisations/mensuelles/route.ts
import { NextResponse } from "next/server";
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { getUserPermissions, canAccessCotisations, checkPermissionOrRespond } from "@/lib/permissions";

export const dynamic = 'force-dynamic';
export const revalidate = 0;
export const runtime = 'nodejs';

type Ligne = {
  mois: number;
  annee: number;
  status?: 'avenir' | 'en_cours' | 'ok';
  segment?: string | null; // ex: RG, Intermittents
  total: number;
  urssaf: number;
  fts: number; // France Travail Spectacle (ex Pôle Emploi Spectacle)
  audiens_retraite: number;
  audiens_prevoyance: number;
  conges_spectacles: number;
  prevoyance_rg: number;
  pas: number;
};

const FR_MONTHS: Record<string, number> = {
  jan: 1, janvier: 1,
  fev: 2, fév: 2, fevrier: 2, février: 2,
  mar: 3, mars: 3,
  avr: 4, avril: 4,
  mai: 5,
  jun: 6, juin: 6,
  jul: 7, juil: 7, juillet: 7,
  aou: 8, août: 8, aout: 8,
  sep: 9, sept: 9, septembre: 9,
  oct: 10, octobre: 10,
  nov: 11, novembre: 11,
  dec: 12, décembre: 12, decembre: 12,
};

function parsePeriodLabel(label?: string | null): { y?: number; m?: number } {
  if (!label) return {};
  const s = label.toString().trim().toLowerCase();
  const parts = s.split(/\s+/);
  let y: number | undefined;
  let m: number | undefined;
  for (const p of parts) {
    const mm = FR_MONTHS[p];
    if (mm) m = mm;
    const yMatch = p.match(/^(19|20)\d{2}$/);
    if (yMatch) y = parseInt(yMatch[0], 10);
  }
  return { y, m };
}

function getPaymentStatusForPeriod(y: number, m: number, today: Date): 'avenir' | 'en_cours' | 'ok' {
  // Payment window: 15 → 30 of the following month
  const nextMonth = m === 12 ? 1 : m + 1;
  const nextYear = m === 12 ? y + 1 : y;
  const start = new Date(nextYear, nextMonth - 1, 15, 0, 0, 0, 0);
  const lastDayOfNextMonth = new Date(nextYear, nextMonth, 0).getDate();
  const endDay = Math.min(30, lastDayOfNextMonth);
  const end = new Date(nextYear, nextMonth - 1, endDay, 23, 59, 59, 999);
  if (today < start) return 'avenir';
  if (today <= end) return 'en_cours';
  return 'ok'; // après la fenêtre → considéré payé/OK par convention
}

async function getOrganizationFromDatabase(supabase: any, userId: string) {
  try {
    const { data: memberData } = await supabase
      .from('organization_members')
      .select('org_id')
      .eq('user_id', userId)
      .single();
    if (!memberData?.org_id) return null;
    const { data: orgData } = await supabase
      .from('organizations')
      .select('structure_api')
      .eq('id', memberData.org_id)
      .single();
    if (!orgData?.structure_api) return null;
    return { id: memberData.org_id as string, name: orgData.structure_api as string, isStaff: false };
  } catch {
    return null;
  }
}

async function getClientInfoFromSession(session: any, supabase: any) {
  const userMeta = session?.user?.user_metadata || {};
  const appMeta = session?.user?.app_metadata || {};

  // Priorité: valeur côté serveur (table staff_users)
  let isStaff = false;
  try {
    const { data: staffRow } = await supabase.from('staff_users').select('is_staff').eq('user_id', session.user.id).maybeSingle();
    isStaff = !!staffRow?.is_staff;
  } catch (e) {
    isStaff = Boolean(
      (userMeta.is_staff === true || userMeta.role === 'staff') ||
      (Array.isArray(appMeta.roles) && appMeta.roles.includes('staff'))
    );
  }

  if (isStaff) {
    const cookieStore = cookies();
    const activeOrgId = cookieStore.get('active_org_id')?.value;
    if (!activeOrgId) {
      return { id: null, name: 'Staff Access', isStaff: true };
    }
    const { data: orgData } = await supabase.from('organizations').select('structure_api').eq('id', activeOrgId).single();
    return { id: activeOrgId, name: orgData?.structure_api || 'Staff Access', isStaff: true };
  }

  const orgInfo = await getOrganizationFromDatabase(supabase, session.user.id);
  if (!orgInfo) throw new Error('User is not associated with any organization');
  return orgInfo;
}

export async function GET(req: Request) {
  try {
    const supabase = createRouteHandlerClient({ cookies });
    
    // 🔒 VÉRIFICATION DES PERMISSIONS
    const permissions = await getUserPermissions(supabase);
    const permissionCheck = canAccessCotisations(permissions);
    const errorResponse = checkPermissionOrRespond(permissionCheck);
    if (errorResponse) return errorResponse;
    
    const { searchParams } = new URL(req.url);
    const year = parseInt(searchParams.get('year') || `${new Date().getFullYear()}`, 10);
    const period = (searchParams.get('period') || 'toute_annee').toString();
    const fromParam = searchParams.get('from') || undefined; // YYYY-MM-DD
    const toParam = searchParams.get('to') || undefined;     // YYYY-MM-DD

    const { data: { session } } = await supabase.auth.getSession();
    if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 });

    let clientInfo;
    try {
      clientInfo = await getClientInfoFromSession(session, supabase);
    } catch (e) {
      const message = e instanceof Error ? e.message : String(e);
      return NextResponse.json({ error: 'forbidden', message }, { status: 403 });
    }

    // Si staff, vérifier si un org_id override est fourni via headers (pour le sélecteur d'organisation)
    if (clientInfo.isStaff) {
      const headerOrgId = req.headers.get('x-active-org-id');
      if (headerOrgId) {
        const { data: orgData } = await supabase
          .from('organizations')
          .select('structure_api')
          .eq('id', headerOrgId)
          .single();
        if (orgData) {
          clientInfo = {
            id: headerOrgId,
            name: orgData.structure_api || 'Staff Access',
            isStaff: true
          };
        }
      }
    }

    // Fetch all contributions for org (volume should be acceptable; filter in memory by period)
    let query: any = supabase.from('monthly_contributions').select('*');
    if (clientInfo.id) {
      query = query.eq('org_id', clientInfo.id);
    }
    const { data, error } = await query;

    if (error) {
      console.error('[api/cotisations/mensuelles] supabase error:', error.message);
      return NextResponse.json({ error: 'supabase_error', detail: error.message }, { status: 500 });
    }

    // Determine range of months based on filters
    const monthsAllowed = new Set<number>();
    const addRange = (mStart: number, mEnd: number) => { for (let m = mStart; m <= mEnd; m++) monthsAllowed.add(m); };
    if (period === 'toute_annee') addRange(1, 12);
    else if (period === 'premier_semestre') addRange(1, 6);
    else if (period === 'second_semestre') addRange(7, 12);
    else if (period.startsWith('trimestre_')) {
      const q = parseInt(period.split('_')[1], 10) as 1 | 2 | 3 | 4;
      const start = (q - 1) * 3 + 1; addRange(start, start + 2);
    } else if (period.startsWith('mois_')) {
      const m = parseInt(period.split('_')[1], 10); if (!isNaN(m)) addRange(m, m);
    } else addRange(1, 12);

    const today = new Date();

    // Buckets dynamiques par (mois, segment) pour ne pas agréger RG vs Intermittents
    const byKey: Record<string, Ligne> = {};

    // Date helpers for from/to
    // Force: ignore absolute from/to filtering (requested)
    const fromDate = null;
    const toDate = null;

    for (const r of data || []) {
      // Decide reference period (year, month)
      const { y: yFromLabel, m: mFromLabel } = parsePeriodLabel(r.period_label as string | null);
      let y = yFromLabel;
      let m = mFromLabel;

      // Fallback to due_date → month
      if (!y || !m) {
        const basis = r.due_date || r.paid_date || r.created_at;
        if (basis) {
          const d = new Date(basis);
          if (!isNaN(d.getTime())) {
            y = d.getFullYear();
            m = d.getMonth() + 1;
          }
        }
      }
      if (!y || !m) continue;

      // Filter by selected year and period
      if (y !== year) continue;
      if (!monthsAllowed.has(m)) continue;

      // (from/to ignored for filtering)

      // Amount precedence: due → paid → 0
      const amount = (r.amount_due ?? r.amount_paid ?? 0) as number;

      // Segment/group detection (contrib_type, sinon suffixe dans period_label : "RG" | "Int.")
      const rawType = (r as any).contrib_type ?? (r as any).category ?? (r as any).type ?? (r as any).reference ?? '';
      let segment: string | null = null;
      if (typeof rawType === 'string' && rawType.trim()) segment = rawType.trim();
      // Si non renseigné, inspecter la period_label pour les suffixes usuels
      if (!segment && typeof r.period_label === 'string') {
        const lbl = r.period_label.trim();
        if (/\bRG\b\.?$/.test(lbl)) segment = 'RG';
        else if (/\bInt\.?$/i.test(lbl)) segment = 'Int.'; // conserver l'abréviation visible
      }
      if (!segment) {
        const s = String(r.status || '').toLowerCase();
        if (/\brg\b/.test(s)) segment = 'RG';
        else if (/inter/.test(s)) segment = 'Int.';
      }

      const key = `${y}-${m}-${segment || 'default'}`;
      if (!byKey[key]) {
        byKey[key] = {
          mois: m,
          annee: y,
          segment,
          total: 0,
          urssaf: 0,
          fts: 0,
          audiens_retraite: 0,
          audiens_prevoyance: 0,
          conges_spectacles: 0,
          prevoyance_rg: 0,
          pas: 0,
        };
      }

      // Map funds
      const fund = String(r.fund || '').toUpperCase();
      const row = byKey[key];
      switch (fund) {
        case 'URSSAF': row.urssaf += Number(amount) || 0; break;
        case 'PE_SPECTACLE': row.fts += Number(amount) || 0; break;
        case 'AUDIENS_RETRAITE': row.audiens_retraite += Number(amount) || 0; break;
        case 'AUDIENS_PREVOYANCE': row.audiens_prevoyance += Number(amount) || 0; break;
        case 'CONGES_SPECTACLES': row.conges_spectacles += Number(amount) || 0; break;
        case 'PREVOYANCE_RG': row.prevoyance_rg += Number(amount) || 0; break;
        case 'MUTUELLE_RG': row.prevoyance_rg += Number(amount) || 0; break; // agrégé dans prevoyance RG pour l'UI
        case 'PAS': row.pas += Number(amount) || 0; break;
        default: break;
      }

      // defer status computation to after aggregation
    }

    // Compute totals per (mois, segment)
    Object.values(byKey).forEach((r) => {
      r.total = r.urssaf + r.fts + r.audiens_retraite + r.audiens_prevoyance + r.conges_spectacles + r.prevoyance_rg + r.pas;
    });

    // Compute status per (mois, segment) after aggregation based on window only
    Object.values(byKey).forEach((r) => {
      r.status = getPaymentStatusForPeriod(r.annee, r.mois, today);
    });

    // Build only periods that exist; sort desc (recent → ancien), puis segment alpha
    const items: Ligne[] = Object.values(byKey)
      .filter((r) => monthsAllowed.has(r.mois))
      .sort((a, b) => {
        if (a.annee !== b.annee) return b.annee - a.annee;
        if (a.mois !== b.mois) return b.mois - a.mois;
        const sa = (a.segment || '').toLowerCase();
        const sb = (b.segment || '').toLowerCase();
        return sa.localeCompare(sb);
      });

    // Total line
    const total: Ligne = items.reduce<Ligne>((acc, r) => ({
      mois: 0,
      annee: year,
      status: acc.status || r.status,
      segment: null,
      total: acc.total + r.total,
      urssaf: acc.urssaf + r.urssaf,
      fts: acc.fts + r.fts,
      audiens_retraite: acc.audiens_retraite + r.audiens_retraite,
      audiens_prevoyance: acc.audiens_prevoyance + r.audiens_prevoyance,
      conges_spectacles: acc.conges_spectacles + r.conges_spectacles,
      prevoyance_rg: acc.prevoyance_rg + r.prevoyance_rg,
      pas: acc.pas + r.pas,
    }), { mois: 0, annee: year, status: undefined, segment: null, total: 0, urssaf: 0, fts: 0, audiens_retraite: 0, audiens_prevoyance: 0, conges_spectacles: 0, prevoyance_rg: 0, pas: 0 });

    return NextResponse.json({ items, total });
  } catch (e: any) {
    const message = e?.message || 'unknown';
    return NextResponse.json({ error: 'internal_server_error', message }, { status: 500 });
  }
}
