// app/(app)/virements-salaires/page.tsx
"use client";
import React, { useMemo, useState, useEffect } from "react";
import { useSearchParams, usePathname, useRouter } from "next/navigation";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Loader2, Search, Download, ExternalLink, Info, Copy, Check, X } from "lucide-react";
import { usePageTitle } from "@/hooks/usePageTitle";
import { useDemoMode } from "@/hooks/useDemoMode";
import { useStaffOrgSelection } from "@/hooks/useStaffOrgSelection";

// --- Types ---
type PeriodKey =
  | "toute_annee"
  | "premier_semestre"
  | "second_semestre"
  | "trimestre_1"
  | "trimestre_2"
  | "trimestre_3"
  | "trimestre_4"
  | `mois_${1|2|3|4|5|6|7|8|9|10|11|12}`;

type Filters = {
  year: number;
  period: PeriodKey;
  from?: string; // YYYY-MM-DD
  to?: string;   // YYYY-MM-DD
};

type VirementItem = {
  id: string;
  periode_label?: string;
  periode?: string;
  callsheet?: string;
  num_appel?: string;
  date_mois?: string;
  date?: string;
  total_salaries_eur?: number;
  total?: number;
  virement_recu?: boolean | string;
  virement_recu_date?: string | null; // Date de réception du virement
  salaires_payes?: boolean | string;
  pdf_url?: string;
};

type OrgSummary = {
  structure_api: string | null;
  virements_salaires: string | null;
  iban: string | null;
  bic: string | null;
  gocardless?: string | null;
} | null;

// Vue client (virements gérés par le client)
type ClientVirementItem = {
  id: string;
  kind: 'CDDU_MONO' | 'CDDU_MULTI' | 'RG';
  source: 'contrat' | 'paie_multi' | 'paie_rg' | 'payslip';
  contract_id?: string;
  salarie?: string | null;
  salarie_matricule?: string | null;
  reference?: string | null;
  profession?: string | null;
  date_debut?: string | null;
  date_fin?: string | null;
  periode?: string | null; // ex: "2025-08-01" ou "08/2025"
  net_a_payer?: number | null;
  virement_effectue?: 'oui' | 'non' | 'na';
};

type ClientInfo = {
  id: string;
  name: string;
  api_name?: string;
} | null;

// --- Helpers ---
function pad2(n: number) { return String(n).padStart(2, "0"); }
function monthStartISO(y: number, m: number) { return `${y}-${pad2(m)}-01`; }
function monthEndISO(y: number, m: number) {
  const d = new Date(y, m, 0); // last day of month
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}
function quarterRange(y: number, q: 1 | 2 | 3 | 4) {
  const startMonth = (q - 1) * 3 + 1; 
  const endMonth = startMonth + 2;
  return { from: monthStartISO(y, startMonth), to: monthEndISO(y, endMonth) };
}

function formatFR(iso: string) {
  if (!iso) return "—";
  const d = new Date(iso);
  if (isNaN(d.getTime())) return "—";
  const dd = String(d.getDate()).padStart(2, '0');
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const yyyy = d.getFullYear();
  return `${dd}/${mm}/${yyyy}`;
}

function maskEndDate(iso?: string | null): string | React.ReactNode {
  if (!iso) return '—';
  // Masquer la date 2099-01-01 utilisée comme fin indéterminée (CDI en cours)
  if (iso.startsWith('2099-01-01')) {
    return <span className="text-sm text-slate-400 italic">CDI en cours</span>;
  }
  return formatFR(iso);
}

function capitalize(str: string) {
  if (!str) return str;
  return str.charAt(0).toUpperCase() + str.slice(1);
}

// 🎭 Données fictives pour le mode démo (virements gérés par Odentas)
const DEMO_VIREMENTS: VirementItem[] = [
  {
    id: 'demo-vir-001',
    periode_label: 'Septembre 2025',
    periode: '2025-09',
    callsheet: 'FDR-2025-09',
    num_appel: 'FDR-2025-09',
    date_mois: '2025-09-01',
    date: '2025-09-01',
    total_salaries_eur: 12450.50,
    total: 12450.50,
    virement_recu: true,
    virement_recu_date: '2025-09-15',
    salaires_payes: true,
  },
  {
    id: 'demo-vir-002',
    periode_label: 'Août 2025',
    periode: '2025-08',
    callsheet: 'FDR-2025-08',
    num_appel: 'FDR-2025-08',
    date_mois: '2025-08-01',
    date: '2025-08-01',
    total_salaries_eur: 15230.80,
    total: 15230.80,
    virement_recu: true,
    virement_recu_date: '2025-08-12',
    salaires_payes: true,
  },
  {
    id: 'demo-vir-003',
    periode_label: 'Juillet 2025',
    periode: '2025-07',
    callsheet: 'FDR-2025-07',
    num_appel: 'FDR-2025-07',
    date_mois: '2025-07-01',
    date: '2025-07-01',
    total_salaries_eur: 18765.25,
    total: 18765.25,
    virement_recu: true,
    virement_recu_date: '2025-07-18',
    salaires_payes: true,
  },
  {
    id: 'demo-vir-004',
    periode_label: 'Juin 2025',
    periode: '2025-06',
    callsheet: 'FDR-2025-06',
    num_appel: 'FDR-2025-06',
    date_mois: '2025-06-01',
    date: '2025-06-01',
    total_salaries_eur: 14890.00,
    total: 14890.00,
    virement_recu: true,
    virement_recu_date: '2025-06-14',
    salaires_payes: true,
  },
  {
    id: 'demo-vir-005',
    periode_label: 'Mai 2025',
    periode: '2025-05',
    callsheet: 'FDR-2025-05',
    num_appel: 'FDR-2025-05',
    date_mois: '2025-05-01',
    date: '2025-05-01',
    total_salaries_eur: 11250.75,
    total: 11250.75,
    virement_recu: true,
    virement_recu_date: '2025-05-16',
    salaires_payes: true,
  },
];

// Affiche une période au format "Mois YYYY" (ex: "Septembre 2025")
function formatPeriode(per?: string | null) {
  if (!per) return '—';
  const s = String(per).trim();
  // ISO: YYYY-MM or YYYY-MM-DD
  const mIso = s.match(/^(\d{4})-(\d{2})(?:-(\d{2}))?$/);
  if (mIso) {
    const y = parseInt(mIso[1], 10);
    const m = parseInt(mIso[2], 10);
    const d = new Date(y, (isNaN(m) ? 1 : m) - 1, 1);
    return capitalize(d.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' }));
  }
  // MM/YYYY
  const mMY = s.match(/^(\d{1,2})\/(\d{4})$/);
  if (mMY) {
    const m = parseInt(mMY[1], 10);
    const y = parseInt(mMY[2], 10);
    const d = new Date(y, (isNaN(m) ? 1 : m) - 1, 1);
    return capitalize(d.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' }));
  }
  // Fallback: essayer Date()
  const d = new Date(s);
  if (!isNaN(d.getTime())) {
    return capitalize(d.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' }));
  }
  return s;
}

function formatCurrency(amount?: number) {
  if (amount == null) return "—";
  return new Intl.NumberFormat('fr-FR', {
    style: 'currency',
    currency: 'EUR'
  }).format(amount);
}

function toBoolish(v: any): boolean | undefined {
  if (v === true) return true;
  if (v === false) return false;
  if (typeof v === 'string') {
    const s = v.trim().toLowerCase();
    if (s === 'oui' || s === 'yes' || s === 'true') return true;
    if (s === 'non' || s === 'no' || s === 'false') return false;
  }
  return undefined;
}

// --- Hook pour récupérer les infos utilisateur et les organisations (staff uniquement) ---
function useUserInfo() {
  return useQuery({
    queryKey: ["user-info"],
    queryFn: async () => {
      try {
        const res = await fetch("/api/me", { 
          cache: "no-store", 
          headers: { Accept: "application/json" },
          credentials: "include"
        });
        if (!res.ok) return null;
        const me = await res.json();
        
        return {
          isStaff: Boolean(me.is_staff || me.isStaff),
          orgId: me.orgId || me.active_org_id || null,
          orgName: me.orgName || me.active_org_name || "Organisation",
          api_name: me.active_org_api_name
        };
      } catch {
        return null;
      }
    },
    staleTime: 30_000,
  });
}

function useOrganizations() {
  const { data: userInfo, isSuccess: userInfoLoaded } = useUserInfo();
  
  const query = useQuery({
    queryKey: ["organizations"],
    queryFn: async () => {
      try {
        const res = await fetch("/api/staff/organizations", { 
          cache: "no-store", 
          headers: { Accept: "application/json" },
          credentials: "include"
        });
        if (!res.ok) return [];
        const data = await res.json();
        return data.organizations || [];
      } catch {
        return [];
      }
    },
    enabled: false,
    staleTime: 60_000,
  });

  React.useEffect(() => {
    if (userInfoLoaded && userInfo?.isStaff && !query.data && !query.isFetching) {
      query.refetch();
    }
  }, [userInfo, userInfoLoaded, query]);

  return query;
}

// --- Hook pour récupérer les virements ---
function useVirements(filters: Filters, selectedOrgId?: string, isDemoMode: boolean = false) {
  // Récupération dynamique des infos utilisateur via /api/me
  const { data: userInfo } = useUserInfo();

  const qs = new URLSearchParams();
  qs.set("year", String(filters.year));
  qs.set("period", filters.period);
  if (filters.from) qs.set("from", filters.from);
  if (filters.to) qs.set("to", filters.to);
  
  // Si c'est un staff qui a sélectionné une organisation spécifique
  if (selectedOrgId && userInfo?.isStaff) {
    qs.set("org_id", selectedOrgId);
  }

  return useQuery<{ items: VirementItem[]; enabled?: boolean; org?: OrgSummary; client?: { unpaid: ClientVirementItem[]; recent: ClientVirementItem[] } }>({
    queryKey: ["virements-salaires", filters.year, userInfo?.orgId, selectedOrgId, isDemoMode],
    queryFn: async () => {
      // 🎭 En mode démo, retourner les données fictives
      if (isDemoMode) {
        console.log('🎭 [VIREMENTS] Mode démo - retour de données fictives');
        return {
          items: DEMO_VIREMENTS,
          enabled: true, // Mode Odentas activé en démo
          org: {
            structure_api: 'demo-org',
            virements_salaires: 'odentas',
            iban: 'FR76 1234 5678 9012 3456 7890 123',
            bic: 'ABCDEFGH',
          } as OrgSummary,
          client: undefined,
        };
      }
      
      // On récupère toutes les données de l'année, le filtrage par période se fera côté client
      const simpleQs = new URLSearchParams();
      simpleQs.set("year", String(filters.year));
      simpleQs.set("period", "toute_annee");
      
      // Si c'est un staff qui a sélectionné une organisation spécifique
      if (selectedOrgId && userInfo?.isStaff) {
        simpleQs.set("org_id", selectedOrgId);
      }
      
      const res = await fetch(`/api/virements-salaires?${simpleQs.toString()}`, {
        credentials: "include",
        headers: { Accept: "application/json" }
      });
      if (!res.ok) {
        const text = await res.text();
        throw new Error(text || `Erreur ${res.status}`);
      }
      const data = await res.json();
      return {
        items: (data?.items || []) as VirementItem[],
        enabled: Boolean(data?.enabled),
        org: (data?.org ?? null) as OrgSummary,
        client: data?.client as { unpaid: ClientVirementItem[]; recent: ClientVirementItem[] } | undefined,
      };
    },
    staleTime: 15_000,
    enabled: !!userInfo, // Ne pas exécuter si pas d'infos utilisateur
  });
}

export default function VirementsPage() {
  usePageTitle("Virements salaires");
  
  // 🎭 Détection du mode démo
  const { isDemoMode } = useDemoMode();
  
  // Helper pour valider les UUIDs
  const isValidUUID = (str: string | null): boolean => {
    if (!str) return false;
    return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
  };
  
  // Zustand store pour la sélection d'organisation (staff)
  const { 
    selectedOrgId: globalSelectedOrgId, 
    setSelectedOrg: setGlobalSelectedOrg 
  } = useStaffOrgSelection();
  
  const now = new Date();
  const [filters, setFilters] = useState<Filters>({ 
    year: now.getFullYear(), 
    period: "toute_annee" 
  });
  const [searchQuery, setSearchQuery] = useState("");
  const [aboutOpen, setAboutOpen] = useState(false);
  const [copiedField, setCopiedField] = useState<null | 'iban' | 'bic' | 'benef'>(null);
  // État local initialisé avec la valeur globale si elle est un UUID valide
  const [selectedOrgId, setSelectedOrgId] = useState<string>(
    (globalSelectedOrgId && isValidUUID(globalSelectedOrgId)) ? globalSelectedOrgId : ""
  );
  const [pdfModalOpen, setPdfModalOpen] = useState(false);
  const [pdfUrl, setPdfUrl] = useState<string>("");
  const [undoModalOpen, setUndoModalOpen] = useState(false);
  const [undoPayslipId, setUndoPayslipId] = useState<string | null>(null);
  
  // États pour la sélection et l'export SEPA
  const [selectedPayslips, setSelectedPayslips] = useState<Set<string>>(new Set());
  const [showExportModal, setShowExportModal] = useState(false);
  const [exportWarnings, setExportWarnings] = useState<string[]>([]);
  const [exportSuccess, setExportSuccess] = useState<{
    numberOfTransactions: number;
    totalAmount: string;
    includedPayments: number;
    excludedPayments: number;
  } | null>(null);
  const [isExporting, setIsExporting] = useState(false);
  const [isMarkingPaid, setIsMarkingPaid] = useState(false);
  const [showBulkMarkPaidModal, setShowBulkMarkPaidModal] = useState(false);
  const [showChangeGestionModal, setShowChangeGestionModal] = useState(false);
  const [isChangingGestion, setIsChangingGestion] = useState(false);

  const { data: userInfo, isLoading: isLoadingUser } = useUserInfo();
  const { data: organizations, isLoading: isLoadingOrgs, error: orgsError } = useOrganizations();
  const queryClient = useQueryClient();

  // Synchronisation bidirectionnelle : global → local
  useEffect(() => {
    if (userInfo?.isStaff && globalSelectedOrgId && isValidUUID(globalSelectedOrgId)) {
      setSelectedOrgId(globalSelectedOrgId);
    }
  }, [globalSelectedOrgId, userInfo?.isStaff]);

  const years = useMemo(() => {
    const base = now.getFullYear();
    return Array.from({ length: 7 }, (_, i) => base - i);
  }, [now]);

  // URL sync
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const router = useRouter();

  useEffect(() => {
    const sp = searchParams; 
    if (!sp) return;
    const yParam = sp.get("year");
    const pParam = sp.get("period");
    const from = sp.get("from") || undefined; 
    const to = sp.get("to") || undefined;
    const next: Filters = { ...filters };
    
    if (yParam) { 
      const y = parseInt(yParam, 10); 
      if (!isNaN(y)) next.year = y; 
    }
    
    if (pParam) {
      const allowed = new Set<PeriodKey>([
        "toute_annee", "premier_semestre", "second_semestre",
        "trimestre_1", "trimestre_2", "trimestre_3", "trimestre_4",
        "mois_1", "mois_2", "mois_3", "mois_4", "mois_5", "mois_6",
        "mois_7", "mois_8", "mois_9", "mois_10", "mois_11", "mois_12",
      ] as PeriodKey[]);
      
      if (allowed.has(pParam as PeriodKey)) {
        next.period = pParam as PeriodKey;
        if (!from && !to) {
          const y = next.year;
          if (pParam === "premier_semestre") { 
            next.from = monthStartISO(y, 1); 
            next.to = monthEndISO(y, 6); 
          }
          else if (pParam === "second_semestre") { 
            next.from = monthStartISO(y, 7); 
            next.to = monthEndISO(y, 12); 
          }
          else if (pParam === "trimestre_1") { 
            const r = quarterRange(y, 1); 
            next.from = r.from; 
            next.to = r.to; 
          }
          else if (pParam === "trimestre_2") { 
            const r = quarterRange(y, 2); 
            next.from = r.from; 
            next.to = r.to; 
          }
          else if (pParam === "trimestre_3") { 
            const r = quarterRange(y, 3); 
            next.from = r.from; 
            next.to = r.to; 
          }
          else if (pParam === "trimestre_4") { 
            const r = quarterRange(y, 4); 
            next.from = r.from; 
            next.to = r.to; 
          }
          else if (pParam.startsWith("mois_")) { 
            const m = parseInt(pParam.split("_")[1]!, 10); 
            if (!isNaN(m)) { 
              next.from = monthStartISO(y, m); 
              next.to = monthEndISO(y, m); 
            } 
          }
          else if (pParam === "toute_annee") { 
            next.from = undefined; 
            next.to = undefined; 
          }
        }
      }
    }
    
    next.from = (from as any) ?? next.from; 
    next.to = (to as any) ?? next.to;
    const changed = next.year !== filters.year || next.period !== filters.period || next.from !== filters.from || next.to !== filters.to;
    if (changed) setFilters(next);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchParams?.toString()]);

  useEffect(() => {
    if (!pathname) return;
    const qs = new URLSearchParams();
    qs.set("year", String(filters.year));
    qs.set("period", filters.period);
    if (filters.from) qs.set("from", filters.from);
    if (filters.to) qs.set("to", filters.to);
    router.replace(`${pathname}?${qs.toString()}`, { scroll: false });
  }, [filters, pathname, router]);

  const { data, isLoading, isError, error, isFetching } = useVirements(filters, selectedOrgId, isDemoMode);
  const loadingOrg = isLoading || isFetching || data === undefined;
  const org: OrgSummary = (data?.org ?? null) as OrgSummary;
  
  // Amélioration de la détection du mode Odentas (toujours actif en mode démo)
  const isOdentas = isDemoMode || (!loadingOrg && (
    Boolean(data?.enabled) || 
    (typeof org?.virements_salaires === 'string' && org!.virements_salaires!.toLowerCase().includes('odentas'))
  ));
  
  const gestionLabel = loadingOrg ? "Chargement…" : (isOdentas ? "Odentas" : "Votre structure");
  const items: VirementItem[] = (data?.items ?? []) as VirementItem[];
  const clientUnpaidAll: ClientVirementItem[] = (data?.client?.unpaid ?? []) as ClientVirementItem[];
  const clientRecentAll: ClientVirementItem[] = (data?.client?.recent ?? []) as ClientVirementItem[];

  const clientFilter = (arr: ClientVirementItem[]) => {
    if (!searchQuery.trim()) return arr;
    const q = searchQuery.toLowerCase();
    return arr.filter(it =>
      (it.salarie || '').toLowerCase().includes(q) ||
      (it.reference || '').toLowerCase().includes(q) ||
      (it.profession || '').toLowerCase().includes(q) ||
      (it.periode || '').toLowerCase().includes(q)
    );
  };
  const clientUnpaid = clientFilter(clientUnpaidAll);
  const clientRecent = clientFilter(clientRecentAll);

  // Calcul du total des nets à payer pour les salaires non payés
  const totalNetAPayer = useMemo(() => {
    return clientUnpaid.reduce((sum, item) => {
      return sum + (item.net_a_payer ?? 0);
    }, 0);
  }, [clientUnpaid]);

  // Mutation: marquer un payslip comme viré
  async function markPayslipDone(payslipId: string) {
    try {
      // Optimistic UI: masquer l'élément avant refetch
      // (on ne modifie pas le cache TanStack ici, on refetch directement après)
      await fetch(`/api/virements-salaires/${encodeURIComponent(payslipId)}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ transfer_done: true })
      });
      // Invalider les requêtes liées pour recharger la liste
      await queryClient.invalidateQueries({ queryKey: ["virements-salaires"] });
    } catch (e) {
      console.error('Erreur marquage payslip:', e);
      alert('Erreur lors du marquage du virement.');
    }
  }

  // Mutation: marquer un payslip comme NON viré (annuler)
  async function markPayslipUndone(payslipId: string) {
    try {
      await fetch(`/api/virements-salaires/${encodeURIComponent(payslipId)}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ transfer_done: false })
      });
      // Invalider les requêtes liées pour recharger la liste
      await queryClient.invalidateQueries({ queryKey: ["virements-salaires"] });
      setUndoModalOpen(false);
      setUndoPayslipId(null);
    } catch (e) {
      console.error('Erreur annulation marquage payslip:', e);
      alert('Erreur lors de l\'annulation du marquage du virement.');
    }
  }

  // Ouvrir la modale de confirmation pour annuler un marquage
  function openUndoModal(payslipId: string) {
    setUndoPayslipId(payslipId);
    setUndoModalOpen(true);
  }

  // Gestion de la sélection de payslips
  function togglePayslipSelection(payslipId: string) {
    setSelectedPayslips(prev => {
      const next = new Set(prev);
      if (next.has(payslipId)) {
        next.delete(payslipId);
      } else {
        next.add(payslipId);
      }
      return next;
    });
  }

  function toggleSelectAll() {
    if (selectedPayslips.size === clientUnpaid.length && clientUnpaid.length > 0) {
      setSelectedPayslips(new Set());
    } else {
      const allIds = clientUnpaid
        .filter(item => item.source === 'payslip' && item.id)
        .map(item => item.id);
      setSelectedPayslips(new Set(allIds));
    }
  }

  // Export SEPA
  async function handleExportSepa() {
    if (selectedPayslips.size === 0) {
      alert('Veuillez sélectionner au moins une fiche de paie');
      return;
    }

    setIsExporting(true);
    try {
      const response = await fetch('/api/virements-salaires/export-sepa', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({
          payslipIds: Array.from(selectedPayslips),
          organizationId: selectedOrgId
        })
      });

      const result = await response.json();

      if (!response.ok) {
        if (result.employeesWithoutIBAN && result.employeesWithoutIBAN.length > 0) {
          setExportWarnings(result.employeesWithoutIBAN);
          setExportSuccess(null);
          setShowExportModal(true);
        } else {
          throw new Error(result.message || 'Erreur lors de l\'export');
        }
        return;
      }

      // Préparer les données de succès
      setExportSuccess({
        numberOfTransactions: result.metadata.numberOfTransactions,
        totalAmount: result.metadata.totalAmount,
        includedPayments: result.metadata.includedPayments || result.metadata.numberOfTransactions,
        excludedPayments: result.metadata.excludedPayments || 0
      });

      // Si des salariés n'ont pas d'IBAN mais que d'autres oui
      if (result.metadata?.employeesWithoutIBAN && result.metadata.employeesWithoutIBAN.length > 0) {
        setExportWarnings(result.metadata.employeesWithoutIBAN);
      } else {
        setExportWarnings([]);
      }

      // Afficher le modal de succès
      setShowExportModal(true);

      // Télécharger le fichier XML
      const blob = new Blob([result.xml], { type: 'application/xml' });
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = `virements_sepa_${result.metadata.messageId}.xml`;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);

      // Décocher les payslips après export réussi
      setSelectedPayslips(new Set());
      
    } catch (error) {
      console.error('Erreur export SEPA:', error);
      alert(error instanceof Error ? error.message : 'Erreur lors de l\'export SEPA');
    } finally {
      setIsExporting(false);
    }
  }

  // Marquage groupé des paies comme payées
  async function handleBulkMarkPaid() {
    if (selectedPayslips.size === 0) {
      alert('Veuillez sélectionner au moins une fiche de paie');
      return;
    }

    setShowBulkMarkPaidModal(true);
  }

  async function confirmBulkMarkPaid() {
    setShowBulkMarkPaidModal(false);
    setIsMarkingPaid(true);
    try {
      const promises = Array.from(selectedPayslips).map(payslipId =>
        fetch(`/api/virements-salaires/${encodeURIComponent(payslipId)}`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
          credentials: 'include',
          body: JSON.stringify({ transfer_done: true })
        })
      );

      await Promise.all(promises);
      
      // Invalider les requêtes pour recharger la liste
      await queryClient.invalidateQueries({ queryKey: ["virements-salaires"] });
      
      // Réinitialiser la sélection
      setSelectedPayslips(new Set());
      
    } catch (error) {
      console.error('Erreur marquage groupé:', error);
      alert('Erreur lors du marquage groupé des virements');
    } finally {
      setIsMarkingPaid(false);
    }
  }

  // Changement de gestion des virements
  async function handleChangeGestion() {
    if (!org || !selectedOrgId) return;
    setShowChangeGestionModal(false);
    setIsChangingGestion(true);
    
    try {
      const currentMode = isOdentas ? 'odentas' : 'client';
      const newMode = isOdentas ? 'client' : 'odentas';
      
      const response = await fetch('/api/virements-salaires/change-gestion', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({
          organizationId: selectedOrgId,
          newMode
        })
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message || 'Erreur lors du changement de gestion');
      }

      // Recharger les données
      await queryClient.invalidateQueries({ queryKey: ["virements-salaires"] });
      
    } catch (error) {
      console.error('Erreur changement gestion:', error);
      alert(error instanceof Error ? error.message : 'Erreur lors du changement de gestion');
    } finally {
      setIsChangingGestion(false);
    }
  }

  // Filtrage local pour la recherche ET la période
  const filteredItems = useMemo((): VirementItem[] => {
    let result: VirementItem[] = items;
    
    // 1. Filtrage par année (toujours actif)
    result = result.filter((item: VirementItem) => {
      if (!item.date_mois) return false;
      const [year] = item.date_mois.split('-').map(Number);
      return year === filters.year;
    });
    
    // 2. Filtrage par période spécifique (si pas "toute_annee")
    if (filters.period !== "toute_annee") {
      result = result.filter((item: VirementItem) => {
        if (!item.date_mois) return false;
        
        const [, month] = item.date_mois.split('-').map(Number);
        
        switch (filters.period) {
          case "premier_semestre":
            return month >= 1 && month <= 6;
          case "second_semestre":
            return month >= 7 && month <= 12;
          case "trimestre_1":
            return month >= 1 && month <= 3;
          case "trimestre_2":
            return month >= 4 && month <= 6;
          case "trimestre_3":
            return month >= 7 && month <= 9;
          case "trimestre_4":
            return month >= 10 && month <= 12;
          default:
            // Pour les mois individuels (mois_1, mois_2, etc.)
            if (filters.period.startsWith("mois_")) {
              const targetMonth = parseInt(filters.period.split("_")[1]!, 10);
              return month === targetMonth;
            }
            return true;
        }
      });
    }
    
    // 3. Filtrage par recherche textuelle
    if (searchQuery.trim()) {
      const query = searchQuery.toLowerCase();
      result = result.filter((item: VirementItem) => 
        (item.callsheet || item.num_appel || "").toLowerCase().includes(query) ||
        (item.periode_label || item.periode || "").toLowerCase().includes(query)
      );
    }
    
    return result;
  }, [items, searchQuery, filters.period, filters.year]);

  return (
    <div className="space-y-5">
      {/* En-tête + Recherche */}
      <section className="rounded-2xl border bg-white p-4">
        <div className="flex flex-col sm:flex-row sm:items-center gap-3">
          <div>
            <h1 className="text-xl font-semibold">Virements de salaires</h1>
            <p className="text-sm text-slate-600 mt-1">
              Suivez vos appels à virement, l'état des virements reçus et les salaires payés.
            </p>
          </div>
          {isOdentas && (
            <div className="sm:ml-auto flex items-center gap-2 w-full sm:w-auto">
              <div className="flex items-center gap-2 px-3 py-2 rounded-xl border w-full sm:w-80">
                <Search className="w-4 h-4" />
                <input 
                  value={searchQuery} 
                  onChange={(e) => setSearchQuery(e.target.value)} 
                  placeholder="N° appel, période…" 
                  className="bg-transparent outline-none text-sm flex-1" 
                />
              </div>
            </div>
          )}
        </div>

        {/* 🎭 Message informatif en mode démo */}
        {isDemoMode && (
          <div className="mt-4 rounded-xl border-2 border-amber-200 bg-gradient-to-r from-amber-50 to-orange-50 p-3 shadow-sm">
            <div className="flex items-center gap-3">
              <div className="rounded-lg bg-amber-100 p-2">
                <Info className="h-5 w-5 text-amber-700" />
              </div>
              <h3 className="font-semibold text-amber-900">Mode démonstration</h3>
            </div>
          </div>
        )}

        {/* Filtres de période */}
        <div className="mt-4 flex flex-col sm:flex-row sm:items-stretch gap-3">
          <div className="flex items-center gap-2">
            <label className="text-sm font-medium">Année :</label>
            <select
              className="px-3 py-2 rounded-lg border bg-white text-sm"
              value={filters.year}
              onChange={(e) => setFilters(f => ({ ...f, year: parseInt(e.target.value, 10) }))}
            >
              {years.map(y => (
                <option key={y} value={y}>{y}</option>
              ))}
            </select>
          </div>
          
          {/* Sélecteur d'organisation (visible uniquement par le staff) */}
          {userInfo?.isStaff && (
            <div className="flex items-center gap-2">
              <label className="text-sm font-medium">Organisation :</label>
              <select
                className="px-3 py-2 rounded-lg border bg-white text-sm min-w-[200px]"
                value={selectedOrgId}
                onChange={(e) => {
                  const newOrgId = e.target.value;
                  setSelectedOrgId(newOrgId);
                  
                  // Synchronisation bidirectionnelle : local → global
                  if (newOrgId) {
                    const selectedOrg = organizations?.find((org: any) => org.id === newOrgId);
                    if (selectedOrg) {
                      setGlobalSelectedOrg(newOrgId, selectedOrg.name);
                    }
                  } else {
                    setGlobalSelectedOrg(null, null);
                  }
                }}
                disabled={!organizations || organizations.length === 0}
              >
                <option value="">
                  {!organizations || organizations.length === 0 
                    ? "Chargement..." 
                    : "Toutes les organisations"}
                </option>
                {organizations && organizations.map((org: any) => (
                  <option key={org.id} value={org.id}>{org.name}</option>
                ))}
              </select>
              {organizations && organizations.length > 0 && (
                <span className="text-xs text-slate-500">({organizations.length})</span>
              )}
            </div>
          )}
          
          {isOdentas && (
            <div className="flex items-center gap-2">
              <label className="text-sm font-medium">Période :</label>
              <select
                className="px-3 py-2 rounded-lg border bg-white text-sm"
                value={filters.period}
                onChange={(e) => setFilters(f => ({ ...f, period: e.target.value as PeriodKey }))}
              >
                <option value="toute_annee">Toute l'année</option>
                <optgroup label="Semestres">
                  <option value="premier_semestre">Premier semestre</option>
                  <option value="second_semestre">Second semestre</option>
                </optgroup>
                <optgroup label="Trimestres">
                  <option value="trimestre_1">Trimestre 1</option>
                  <option value="trimestre_2">Trimestre 2</option>
                  <option value="trimestre_3">Trimestre 3</option>
                  <option value="trimestre_4">Trimestre 4</option>
                </optgroup>
                <optgroup label="Mois">
                  {[...Array(12)].map((_, i) => (
                    <option key={i + 1} value={`mois_${i + 1}` as PeriodKey}>
                      {new Date(2023, i).toLocaleDateString('fr-FR', { month: 'long' })}
                    </option>
                  ))}
                </optgroup>
              </select>
            </div>
          )}
          <div className="sm:ml-auto min-w-[280px] max-w-sm flex-1">
            <div className="h-full rounded-xl border bg-white p-3">
              <div className="flex items-start justify-between">
                <div>
                  <div className="text-sm font-semibold">Gestion des virements</div>
                  <div className="text-xs text-slate-600">Les virements de salaires sont effectués par</div>
                </div>
                <div className="flex items-center gap-2">
                  <button
                    type="button"
                    onClick={() => setShowChangeGestionModal(true)}
                    disabled={loadingOrg || isChangingGestion}
                    className="text-xs px-2 py-1 rounded-md border hover:bg-slate-50 transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
                  >
                    {isChangingGestion ? 'Modification...' : 'Modifier'}
                  </button>
                </div>
              </div>
              <div className="mt-3 flex items-center justify-between gap-2">
                <div className={`inline-flex items-center gap-2 px-3 py-2 rounded-lg border text-sm ${loadingOrg ? 'bg-slate-50 border-slate-200 text-slate-400' : (isOdentas ? 'bg-emerald-50 border-emerald-200 text-emerald-700' : 'bg-slate-50 border-slate-200 text-slate-700')}`}>
                  <span className="inline-block w-2 h-2 rounded-full" style={{ backgroundColor: isOdentas ? '#10b981' : '#64748b', opacity: loadingOrg ? 0.6 : 1 }} />
                  <span className="font-medium">{gestionLabel}</span>
                </div>
                <button
                  type="button"
                  onClick={() => !loadingOrg && setAboutOpen(true)}
                  disabled={loadingOrg}
                  className={`inline-flex items-center gap-1 text-xs px-2 py-1 rounded-md border transition-colors ${loadingOrg ? 'opacity-50 cursor-not-allowed' : 'hover:bg-slate-50'}`}
                  aria-label="En savoir plus sur les virements"
                >
                  <Info className="w-3.5 h-3.5" />
                  En savoir plus
                </button>
              </div>
            </div>
          </div>
        </div>

      </section>

      {/* Tableau principal */}
      {isOdentas ? (
        <section className="rounded-2xl border bg-white">
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b bg-slate-50/80">
                  <Th>Période</Th>
                  <Th>N° d'appel</Th>
                  <Th>Date d'appel</Th>
                  <Th className="text-right">Salaires nets</Th>
                  <Th className="text-center">Virement reçu</Th>
                  <Th className="text-center">Salaires payés</Th>
                  <Th className="text-center">Document</Th>
                </tr>
              </thead>
              <tbody>
                {isLoading ? (
                  <tr>
                    <td colSpan={7} className="py-12 text-center text-slate-500">
                      <Loader2 className="w-4 h-4 inline animate-spin mr-2" /> 
                      Chargement…
                    </td>
                  </tr>
                ) : isError ? (
                  <tr>
                    <td colSpan={7} className="py-12 text-center text-rose-500">
                      Erreur : {(error as any)?.message || 'imprévue'}
                    </td>
                  </tr>
                ) : filteredItems.length === 0 ? (
                  <tr>
                    <td colSpan={7} className="py-12 text-center text-slate-500">
                      {searchQuery ? 'Aucun virement trouvé pour cette recherche.' : 'Aucun virement de salaires trouvé.'}
                    </td>
                  </tr>
                ) : (
                  filteredItems.map((row: VirementItem) => (
                    <tr key={row.id} className="border-b last:border-b-0 hover:bg-slate-50/50">
                      <Td>{row.periode_label || formatPeriode(row.periode) || "—"}</Td>
                      <Td>
                        <span className="font-medium">
                          {row.num_appel || row.callsheet || "—"}
                        </span>
                      </Td>
                      <Td>{formatFR(row.date_mois || row.date || "")}</Td>
                      <Td className="text-right font-medium">
                        {formatCurrency(row.total_salaries_eur ?? row.total)}
                      </Td>
                      <Td className="text-center">
                        <StatusBadge status={row.virement_recu} date={row.virement_recu_date} />
                      </Td>
                      <Td className="text-center">
                        <StatusBadge status={row.salaires_payes} />
                      </Td>
                      <Td className="text-center">
                        {row.pdf_url ? (
                          <button 
                            onClick={() => {
                              setPdfUrl(row.pdf_url!);
                              setPdfModalOpen(true);
                            }}
                            className="inline-flex items-center gap-1 px-2 py-1 rounded-lg bg-pink-100 text-pink-700 hover:bg-pink-200 transition-colors text-xs"
                          >
                            <Download className="w-3 h-3" />
                            PDF
                          </button>
                        ) : (
                          <span className="text-slate-400">—</span>
                        )}
                      </Td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </div>

          {/* Footer avec indicateur de chargement */}
          {filteredItems.length > 0 && (
            <div className="p-3 border-t text-right">
              <div className="text-sm text-slate-500">
                {isFetching ? (
                  <span className="inline-flex items-center gap-1">
                    <Loader2 className="w-3 h-3 animate-spin" />
                    Mise à jour…
                  </span>
                ) : (
                  `${filteredItems.length} appel${filteredItems.length > 1 ? 's' : ''} à virement${filteredItems.length > 1 ? 's' : ''} affiché${filteredItems.length > 1 ? 's' : ''}`
                )}
              </div>
            </div>
          )}
        </section>
      ) : (
        <section className="rounded-2xl border bg-white">
          {/* Bouton export SEPA si des payslips sont sélectionnés */}
          {selectedPayslips.size > 0 && (
            <div className="border-b bg-blue-50 px-4 py-3">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-3">
                  <div className="text-sm font-medium text-blue-900">
                    {selectedPayslips.size} paie{selectedPayslips.size > 1 ? 's' : ''} sélectionnée{selectedPayslips.size > 1 ? 's' : ''}
                  </div>
                  <button
                    onClick={() => setSelectedPayslips(new Set())}
                    className="text-xs text-blue-600 hover:text-blue-800 underline"
                  >
                    Tout décocher
                  </button>
                </div>
                <div className="flex items-center gap-3">
                  <button
                    onClick={handleBulkMarkPaid}
                    disabled={isMarkingPaid}
                    className="inline-flex items-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    <Check className="w-4 h-4" />
                    {isMarkingPaid ? 'Marquage en cours...' : 'Marquer comme payé'}
                  </button>
                  <div className="relative group">
                    <button
                      disabled
                      className="inline-flex items-center gap-2 px-4 py-2 bg-slate-300 text-slate-500 rounded-lg cursor-not-allowed opacity-60"
                    >
                      <Download className="w-4 h-4" />
                      Exporter fichier bancaire (SEPA)
                    </button>
                    <div
                      role="tooltip"
                      className="pointer-events-none absolute right-0 top-full mt-2 w-48 px-3 py-2 rounded-lg bg-slate-900 text-white text-xs shadow-lg opacity-0 group-hover:opacity-100 translate-y-1 group-hover:translate-y-0 transition z-10"
                    >
                      Bientôt disponible
                      <div className="absolute -top-1 right-6 w-2 h-2 rotate-45 bg-slate-900" />
                    </div>
                  </div>
                </div>
              </div>
            </div>
          )}
          
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b bg-slate-50/80">
                  <Th className="w-12">
                    <input
                      type="checkbox"
                      checked={selectedPayslips.size > 0 && selectedPayslips.size === clientUnpaid.filter(it => it.source === 'payslip').length}
                      onChange={toggleSelectAll}
                      className="rounded"
                      title="Tout sélectionner / Tout décocher"
                    />
                  </Th>
                  <Th>Salarié·e</Th>
                  <Th>Contrat</Th>
                  <Th>Profession</Th>
                  <Th>Début contrat</Th>
                  <Th>Fin contrat</Th>
                  <Th>Période concernée</Th>
                  <Th className="text-right">Net à payer</Th>
                  <Th className="text-center">Marquer comme payé</Th>
                </tr>
                {/* Sous-header avec le total des nets à payer (salaires non payés) */}
                {!isLoading && !isError && clientUnpaid.length > 0 && (
                  <tr className="bg-gradient-to-r from-indigo-50 to-purple-50 border-b-2 border-indigo-200">
                    <th colSpan={7} className="px-4 py-3 text-left">
                      <div className="flex items-center gap-2">
                        <div className="text-sm font-semibold text-indigo-900">
                          Salaires à payer
                        </div>
                        <div className="text-xs text-indigo-700">
                          ({clientUnpaid.length} salarié{clientUnpaid.length > 1 ? 's' : ''})
                        </div>
                      </div>
                    </th>
                    <th colSpan={2} className="px-4 py-3 text-right">
                      <div className="text-sm font-bold text-indigo-900">
                        Total : {formatCurrency(totalNetAPayer)}
                      </div>
                    </th>
                  </tr>
                )}
              </thead>
              <tbody>
                {/* Unpaid first */}
                {isLoading ? (
                  <tr><td colSpan={8} className="py-12 text-center text-slate-500"><Loader2 className="w-4 h-4 inline animate-spin mr-2"/> Chargement…</td></tr>
                ) : isError ? (
                  <tr><td colSpan={8} className="py-12 text-center text-rose-500">Erreur : {(error as any)?.message || 'imprévue'}</td></tr>
                ) : (clientUnpaid.length === 0 && clientRecent.length === 0) ? (
                  <tr><td colSpan={9} className="py-12 text-center text-slate-500">Aucun virement de salaires trouvé.</td></tr>
                ) : (
                  <>
                    {clientUnpaid.map((it) => (
                      <tr key={`unpaid-${it.source}-${it.id}`} className="border-b last:border-b-0 hover:bg-slate-50/50">
                        <Td>
                          {it.source === 'payslip' ? (
                            <input
                              type="checkbox"
                              checked={selectedPayslips.has(it.id)}
                              onChange={() => togglePayslipSelection(it.id)}
                              className="rounded"
                            />
                          ) : (
                            <div className="w-4"></div>
                          )}
                        </Td>
                        <Td>
                          {it.salarie_matricule ? (
                            <a href={`/salaries/${encodeURIComponent(it.salarie_matricule)}`} target="_blank" rel="noreferrer" className="text-blue-600 hover:underline font-medium">
                              {it.salarie || it.salarie_matricule}
                            </a>
                          ) : (
                            it.salarie || '—'
                          )}
                        </Td>
                        <Td>
                          {it.contract_id && it.reference ? (
                            <a
                              href={it.kind === 'RG' ? `/contrats-rg/${encodeURIComponent(it.contract_id)}` : (it.kind === 'CDDU_MULTI' ? `/contrats-multi/${encodeURIComponent(it.contract_id)}` : `/contrats/${encodeURIComponent(it.contract_id)}`)}
                              target="_blank"
                              rel="noreferrer"
                              className="text-blue-600 hover:underline font-medium"
                            >
                              {it.reference}
                            </a>
                          ) : (
                            <span className="font-medium">{it.reference || '—'}</span>
                          )}
                        </Td>
                        <Td>{it.profession || '—'}</Td>
                        <Td>{formatFR(it.date_debut || '')}</Td>
                        <Td>{maskEndDate(it.date_fin || '')}</Td>
                        <Td>{formatPeriode(it.periode)}</Td>
                        <Td className="text-right font-medium">{it.net_a_payer != null ? formatCurrency(it.net_a_payer) : '—'}</Td>
                        <Td className="text-center">
                          {it.source === 'payslip' ? (
                            <button
                              type="button"
                              onClick={() => markPayslipDone(it.id)}
                              className="px-2 py-1 text-xs rounded-md border hover:bg-emerald-50 hover:border-emerald-300 text-emerald-700"
                              title="Marquer le virement comme effectué"
                            >
                              Marquer
                            </button>
                          ) : (
                            <button type="button" disabled className="px-2 py-1 text-xs rounded-md border opacity-60 cursor-not-allowed" title="Non disponible">Marquer</button>
                          )}
                        </Td>
                      </tr>
                    ))}
                    {clientRecent.length > 0 && (
                      <>
                        {/* Séparation visuelle renforcée */}
                        <tr>
                          <td colSpan={8} className="h-4 bg-slate-100"></td>
                        </tr>
                        <tr className="bg-gradient-to-r from-emerald-50 to-green-50 border-y-2 border-emerald-200">
                          <td colSpan={8} className="px-4 py-3">
                            <div className="flex items-center gap-3">
                              <div className="flex items-center justify-center w-8 h-8 rounded-full bg-emerald-100">
                                <Check className="w-5 h-5 text-emerald-700" />
                              </div>
                              <div>
                                <div className="font-semibold text-emerald-900">Virements récemment effectués</div>
                                <div className="text-xs text-emerald-700">Paies virées au cours des 30 derniers jours</div>
                                <div className="text-xs text-emerald-600 italic mt-1">
                                  Si vous avez noté une paie comme payée par erreur, cliquez sur "Oui" pour la noter comme non-payée.
                                </div>
                              </div>
                            </div>
                          </td>
                        </tr>
                      </>
                    )}
                    {clientRecent.map((it) => (
                      <tr key={`recent-${it.source}-${it.id}`} className="border-b last:border-b-0 hover:bg-slate-50/50">
                        <Td><span></span></Td>
                        <Td>
                          {it.salarie_matricule ? (
                            <a href={`/salaries/${encodeURIComponent(it.salarie_matricule)}`} target="_blank" rel="noreferrer" className="text-blue-600 hover:underline font-medium">
                              {it.salarie || it.salarie_matricule}
                            </a>
                          ) : (
                            it.salarie || '—'
                          )}
                        </Td>
                        <Td>
                          {it.contract_id && it.reference ? (
                            <a
                              href={it.kind === 'RG' ? `/contrats-rg/${encodeURIComponent(it.contract_id)}` : (it.kind === 'CDDU_MULTI' ? `/contrats-multi/${encodeURIComponent(it.contract_id)}` : `/contrats/${encodeURIComponent(it.contract_id)}`)}
                              target="_blank"
                              rel="noreferrer"
                              className="text-blue-600 hover:underline font-medium"
                            >
                              {it.reference}
                            </a>
                          ) : (
                            <span className="font-medium">{it.reference || '—'}</span>
                          )}
                        </Td>
                        <Td>{it.profession || '—'}</Td>
                        <Td>{formatFR(it.date_debut || '')}</Td>
                        <Td>{maskEndDate(it.date_fin || '')}</Td>
                        <Td>{formatPeriode(it.periode)}</Td>
                        <Td className="text-right font-medium">{it.net_a_payer != null ? formatCurrency(it.net_a_payer) : '—'}</Td>
                        <Td className="text-center">
                          {it.source === 'payslip' ? (
                            <button
                              type="button"
                              onClick={() => openUndoModal(it.id)}
                              className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-emerald-100 text-emerald-800 hover:bg-emerald-200 transition-colors cursor-pointer"
                              title="Cliquez pour annuler le marquage de ce virement"
                            >
                              Oui
                            </button>
                          ) : (
                            <span className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-emerald-100 text-emerald-800">Oui</span>
                          )}
                        </Td>
                      </tr>
                    ))}
                  </>
                )}
              </tbody>
            </table>
          </div>
        </section>
      )}
      {aboutOpen && (
        <div className="fixed inset-0 z-[1000]">
          <div
            className="absolute inset-0 bg-black/40"
            onClick={() => setAboutOpen(false)}
          />
          <div className="absolute inset-0 flex items-center justify-center p-4">
            <div role="dialog" aria-modal="true" aria-labelledby="about-virements-title" className="w-full max-w-lg rounded-2xl border bg-white shadow-xl">
              <div className="p-5 border-b flex items-start justify-between">
                <div>
                  <h2 id="about-virements-title" className="text-base font-semibold">Gestion des virements de salaires</h2>
                </div>
                <button onClick={() => setAboutOpen(false)} className="text-slate-500 hover:text-slate-900">✕</button>
              </div>
              <div className="p-5 space-y-4 text-sm">
                {/* Card informative pour tous les clients */}
                <div className="rounded-lg border border-blue-200 bg-blue-50 p-4">
                  <div className="flex items-start gap-3">
                    <div className="rounded-lg bg-blue-100 p-2 mt-0.5">
                      <Info className="h-4 w-4 text-blue-700" />
                    </div>
                    <div className="flex-1">
                      <p className="text-sm text-blue-900">
                        Les informations ci-dessous ne concernent que les clients ayant confié la gestion de leurs virements de salaires à Odentas. Vous pouvez nous confier cette gestion sans surcoût, contactez-nous pour plus d'informations.
                      </p>
                    </div>
                  </div>
                </div>

                <p>
                 En fin de mois, nous vous envoyons un <strong>appel à virement</strong> avec le <strong>total des salaires nets</strong> de la période concernée.
                </p>
                <p>
                  Dès réception de votre virement, nous <strong>redistribuons les salaires à vos salariés</strong>. Vous pouvez suivre l’état dans le tableau ci-dessous (colonnes « Virement reçu » et « Salaires payés »).
                </p>
                <div className="rounded-lg border p-3">
                  <div className="text-xs uppercase tracking-wide text-slate-500 mb-2">Coordonnées bancaires (salaires)</div>
                  {isDemoMode ? (
                    <div className="flex flex-col gap-2">
                      <div className="flex items-center justify-center rounded-md bg-slate-50 px-4 py-8">
                        <div className="text-center">
                          <div className="text-sm text-slate-600 mb-1">Mode démonstration</div>
                          <div className="text-xs text-slate-500">Les coordonnées bancaires sont masquées</div>
                        </div>
                      </div>
                      <p className="text-xs text-slate-500 mt-2">Ce compte bancaire est réservé à la réception des virements de salaires.</p>
                    </div>
                  ) : (
                  <div className="flex flex-col gap-2">
                    <div className="flex items-center justify-between gap-2 rounded-md bg-slate-50 px-2 py-2">
                      <div>
                        <div className="text-[11px] text-slate-500">Bénéficiaire</div>
                        <div className="font-mono text-xs break-all">ODENTAS MEDIA SAS</div>
                      </div>
                      <button
                        type="button"
                        onClick={() => { navigator.clipboard?.writeText('ODENTAS MEDIA SAS').then(()=>{ setCopiedField('benef'); setTimeout(()=>setCopiedField(null), 1400); }); }}
                        className="inline-flex items-center gap-1 text-xs px-2 py-1 rounded-md border hover:bg-slate-100"
                        aria-label="Copier le bénéficiaire"
                      >
                        {copiedField === 'benef' ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />} Copier
                      </button>
                    </div>
                    <div className="flex items-center justify-between gap-2 rounded-md bg-slate-50 px-2 py-2">
                      <div>
                        <div className="text-[11px] text-slate-500">IBAN</div>
                        <div className="font-mono text-xs break-all">FR76 1695 8000 0141 0850 9729 813</div>
                      </div>
                      {org?.iban && (
                        <button
                          type="button"
                          onClick={() => { navigator.clipboard?.writeText("FR76 1695 8000 0141 0850 9729 813" as string).then(()=>{ setCopiedField('iban'); setTimeout(()=>setCopiedField(null), 1400); }); }}
                          className="inline-flex items-center gap-1 text-xs px-2 py-1 rounded-md border hover:bg-slate-100"
                          aria-label="Copier l’IBAN"
                        >
                          {copiedField === 'iban' ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />} Copier
                        </button>
                      )}
                    </div>
                    <div className="flex items-center justify-between gap-2 rounded-md bg-slate-50 px-2 py-2">
                      <div>
                        <div className="text-[11px] text-slate-500">BIC</div>
                        <div className="font-mono text-xs break-all">QNTOFRP1XXX</div>
                      </div>
                      {org?.bic && (
                        <button
                          type="button"
                          onClick={() => { navigator.clipboard?.writeText("QNTOFRP1XXX" as string).then(()=>{ setCopiedField('bic'); setTimeout(()=>setCopiedField(null), 1400); }); }}
                          className="inline-flex items-center gap-1 text-xs px-2 py-1 rounded-md border hover:bg-slate-100"
                          aria-label="Copier le BIC"
                        >
                          {copiedField === 'bic' ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />} Copier
                        </button>
                      )}
                    </div>
                    <p className="text-xs text-slate-500 mt-2">Ce compte bancaire est réservé à la réception des virements de salaires.</p>
                  </div>
                )}
                </div>
              </div>
              <div className="p-4 border-t flex justify-end">
                <button onClick={() => setAboutOpen(false)} className="px-3 py-2 rounded-md border hover:bg-slate-50 text-sm">Fermer</button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Modal de changement de gestion des virements */}
      {showChangeGestionModal && (
        <div className="fixed inset-0 z-[1000]">
          <div
            className="absolute inset-0 bg-black/40"
            onClick={() => setShowChangeGestionModal(false)}
          />
          <div className="absolute inset-0 flex items-center justify-center p-4">
            <div role="dialog" aria-modal="true" className="w-full max-w-md rounded-2xl border bg-white shadow-xl">
              <div className="p-5 border-b bg-blue-50">
                <div className="flex items-center gap-3">
                  <div className="rounded-lg bg-blue-100 p-2">
                    <Info className="h-5 w-5 text-blue-700" />
                  </div>
                  <h2 className="text-base font-semibold text-blue-900">
                    Changement de gestion des virements
                  </h2>
                </div>
              </div>
              <div className="p-5 space-y-4 text-sm">
                {isOdentas ? (
                  <>
                    <p className="text-slate-700">
                      Souhaitez-vous reprendre la <strong>gestion de vos virements de salaires</strong> ?
                    </p>
                    <p className="text-slate-600">
                      Vous pourrez effectuer vous-même les virements via votre banque.
                    </p>
                    <div className="rounded-lg bg-green-50 border border-green-200 p-3">
                      <p className="text-sm text-green-900">
                        <strong>Aucune modification tarifaire</strong> - Ce changement n'impacte pas votre facturation.
                      </p>
                    </div>
                  </>
                ) : (
                  <>
                    <p className="text-slate-700">
                      Souhaitez-vous <strong>confier la gestion de vos virements de salaires à Odentas</strong> ?
                    </p>
                    <p className="text-slate-600">
                      Odentas s'occupera de redistribuer les salaires à vos salariés après réception de votre virement mensuel.
                    </p>
                    <div className="rounded-lg bg-green-50 border border-green-200 p-3">
                      <p className="text-sm text-green-900">
                        <strong>Service sans surcoût</strong> - Ce changement n'impacte pas votre facturation.
                      </p>
                    </div>
                  </>
                )}
              </div>
              <div className="p-4 border-t flex justify-end gap-2">
                <button
                  onClick={() => setShowChangeGestionModal(false)}
                  className="px-4 py-2 rounded-lg border hover:bg-slate-50 text-sm transition-colors"
                >
                  Annuler
                </button>
                <button
                  onClick={handleChangeGestion}
                  disabled={isChangingGestion}
                  className="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 text-sm transition-colors disabled:opacity-50"
                >
                  {isChangingGestion ? 'Modification en cours...' : 'Confirmer'}
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Modal PDF */}
      {pdfModalOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
          <div className="bg-white rounded-lg shadow-xl w-full max-w-5xl h-[90vh] flex flex-col">
            <div className="flex items-center justify-between p-4 border-b">
              <h3 className="text-lg font-semibold">Appel à virement - PDF</h3>
              <div className="flex items-center gap-2">
                <a
                  href={pdfUrl}
                  target="_blank"
                  rel="noreferrer"
                  className="inline-flex items-center gap-2 px-3 py-2 text-sm rounded-lg bg-pink-100 text-pink-700 hover:bg-pink-200 transition-colors"
                >
                  <ExternalLink className="w-4 h-4" />
                  Ouvrir dans un nouvel onglet
                </a>
                <button
                  onClick={() => setPdfModalOpen(false)}
                  className="p-2 hover:bg-slate-100 rounded-lg transition-colors"
                  aria-label="Fermer"
                >
                  <X className="w-5 h-5" />
                </button>
              </div>
            </div>
            <div className="flex-1 overflow-hidden bg-slate-100">
              <iframe
                src={`https://docs.google.com/viewer?url=${encodeURIComponent(pdfUrl)}&embedded=true`}
                className="w-full h-full"
                title="PDF Appel à virement"
              />
            </div>
          </div>
        </div>
      )}

      {/* Modal de confirmation pour le marquage groupé */}
      {showBulkMarkPaidModal && (
        <div className="fixed inset-0 z-[1000]">
          <div
            className="absolute inset-0 bg-black/40"
            onClick={() => setShowBulkMarkPaidModal(false)}
          />
          <div className="absolute inset-0 flex items-center justify-center p-4">
            <div role="dialog" aria-modal="true" className="w-full max-w-md rounded-2xl border bg-white shadow-xl">
              <div className="p-5 border-b bg-green-50">
                <div className="flex items-center gap-3">
                  <div className="rounded-lg bg-green-100 p-2">
                    <Check className="h-5 w-5 text-green-700" />
                  </div>
                  <h2 className="text-base font-semibold text-green-900">Marquer comme payé</h2>
                </div>
              </div>
              <div className="p-5 space-y-4 text-sm">
                <p className="text-slate-700">
                  Voulez-vous vraiment marquer <strong>{selectedPayslips.size} paie{selectedPayslips.size > 1 ? 's' : ''}</strong> comme payée{selectedPayslips.size > 1 ? 's' : ''} ?
                </p>
                <p className="text-slate-600">
                  En cas d'erreur, vous pourrez marquer la paie comme non payée à tout moment.
                </p>
              </div>
              <div className="p-4 border-t flex justify-end gap-2">
                <button
                  onClick={() => setShowBulkMarkPaidModal(false)}
                  className="px-4 py-2 rounded-lg border hover:bg-slate-50 text-sm transition-colors"
                >
                  Annuler
                </button>
                <button
                  onClick={confirmBulkMarkPaid}
                  disabled={isMarkingPaid}
                  className="px-4 py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm transition-colors disabled:opacity-50"
                >
                  {isMarkingPaid ? 'Marquage en cours...' : 'Confirmer'}
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Modal de confirmation pour annuler le marquage */}
      {undoModalOpen && undoPayslipId && (
        <div className="fixed inset-0 z-[1000]">
          <div
            className="absolute inset-0 bg-black/40"
            onClick={() => {
              setUndoModalOpen(false);
              setUndoPayslipId(null);
            }}
          />
          <div className="absolute inset-0 flex items-center justify-center p-4">
            <div role="dialog" aria-modal="true" className="w-full max-w-md rounded-2xl border bg-white shadow-xl">
              <div className="p-5 border-b">
                <h2 className="text-base font-semibold">Annuler le marquage du virement</h2>
              </div>
              <div className="p-5 space-y-4 text-sm">
                <p>
                  Êtes-vous sûr de vouloir marquer cette paie comme <strong>non payée</strong> ?
                </p>
                <p className="text-slate-600">
                  Elle réapparaîtra dans la liste des paies à payer.
                </p>
              </div>
              <div className="p-4 border-t flex justify-end gap-2">
                <button
                  onClick={() => {
                    setUndoModalOpen(false);
                    setUndoPayslipId(null);
                  }}
                  className="px-3 py-2 rounded-md border hover:bg-slate-50 text-sm"
                >
                  Annuler
                </button>
                <button
                  onClick={() => markPayslipUndone(undoPayslipId)}
                  className="px-3 py-2 rounded-md bg-orange-600 text-white hover:bg-orange-700 text-sm"
                >
                  Confirmer
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Modal d'avertissement pour les salariés sans IBAN */}
      {showExportModal && (
        <div className="fixed inset-0 z-[1000]">
          <div
            className="absolute inset-0 bg-black/40"
            onClick={() => {
              setShowExportModal(false);
              setExportSuccess(null);
              setExportWarnings([]);
            }}
          />
          <div className="absolute inset-0 flex items-center justify-center p-4">
            <div role="dialog" aria-modal="true" className="w-full max-w-lg rounded-2xl border bg-white shadow-xl">
              {/* Header avec succès ou erreur */}
              {exportSuccess ? (
                <div className="p-5 border-b bg-green-50">
                  <div className="flex items-center gap-3">
                    <div className="rounded-lg bg-green-100 p-2">
                      <Check className="h-5 w-5 text-green-700" />
                    </div>
                    <div>
                      <h2 className="text-base font-semibold text-green-900">Fichier SEPA généré avec succès !</h2>
                      <p className="text-sm text-green-700">Le téléchargement a démarré automatiquement</p>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="p-5 border-b bg-red-50">
                  <div className="flex items-center gap-3">
                    <div className="rounded-lg bg-red-100 p-2">
                      <X className="h-5 w-5 text-red-700" />
                    </div>
                    <h2 className="text-base font-semibold text-red-900">Export impossible</h2>
                  </div>
                </div>
              )}
              
              <div className="p-5 space-y-4 text-sm">
                {/* Résumé de l'export si succès */}
                {exportSuccess && (
                  <div className="bg-slate-50 rounded-lg p-4 space-y-2">
                    <div className="flex justify-between items-center">
                      <span className="text-slate-600">Nombre de virements :</span>
                      <span className="font-semibold text-slate-900">{exportSuccess.numberOfTransactions}</span>
                    </div>
                    <div className="flex justify-between items-center">
                      <span className="text-slate-600">Montant total :</span>
                      <span className="font-semibold text-slate-900">{exportSuccess.totalAmount} €</span>
                    </div>
                    {exportSuccess.excludedPayments > 0 && (
                      <>
                        <div className="border-t border-slate-200 my-2"></div>
                        <div className="flex justify-between items-center text-amber-700">
                          <span>Salariés inclus :</span>
                          <span className="font-semibold">{exportSuccess.includedPayments}</span>
                        </div>
                        <div className="flex justify-between items-center text-amber-700">
                          <span>Salariés exclus (sans RIB) :</span>
                          <span className="font-semibold">{exportSuccess.excludedPayments}</span>
                        </div>
                      </>
                    )}
                  </div>
                )}

                {/* Liste des salariés sans RIB */}
                {exportWarnings.length > 0 && (
                  <>
                    <div className={`${exportSuccess ? 'border-t border-slate-200 pt-4' : ''}`}>
                      <p className="text-slate-700 font-medium mb-2">
                        {exportSuccess ? 'Salariés exclus (sans RIB) :' : 'Tous les salariés sélectionnés n\'ont pas de RIB :'}
                      </p>
                      <ul className="list-disc list-inside space-y-1 text-slate-600 bg-amber-50 rounded-lg p-3 border border-amber-200">
                        {exportWarnings.map((name, index) => (
                          <li key={index}>{name}</li>
                        ))}
                      </ul>
                      <p className="text-slate-600 mt-3">
                        Ces salariés doivent <strong>envoyer leur RIB depuis leur Espace Transat</strong> pour pouvoir être inclus dans les prochains exports de virements.
                      </p>
                    </div>
                  </>
                )}
              </div>
              
              <div className="p-4 border-t flex justify-end">
                <button
                  onClick={() => {
                    setShowExportModal(false);
                    setExportSuccess(null);
                    setExportWarnings([]);
                  }}
                  className="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 text-sm"
                >
                  {exportSuccess ? 'Fermer' : 'J\'ai compris'}
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// --- Composants utilitaires ---
function Th({ children, className = "" }: { children: React.ReactNode; className?: string }) {
  return (
    <th className={`text-left font-medium px-3 py-3 ${className}`}>
      {children}
    </th>
  );
}

function Td({ children, className = "" }: { children: React.ReactNode; className?: string }) {
  return (
    <td className={`px-3 py-3 ${className}`}>
      {children}
    </td>
  );
}

function StatusBadge({ status, date }: { status?: boolean | string; date?: string | null }) {
  const val = toBoolish(status);
  if (val === true) {
    return (
      <div className="flex flex-col items-center gap-1">
        <span className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-emerald-100 text-emerald-800">
          ✓ Oui
        </span>
        {date && (
          <span className="text-[10px] text-slate-500">
            {formatFR(date)}
          </span>
        )}
      </div>
    );
  } else if (val === false) {
    return (
      <span className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-slate-100 text-slate-600">
        ✗ Non
      </span>
    );
  } else {
    return <span className="text-slate-400">—</span>;
  }
}
