"use client";

import { useEffect, useMemo, useState, useRef } from "react";
import { supabase } from "@/lib/supabaseClient";
import Link from "next/link";
import { RefreshCw, Check, X, Eye, Plus, CheckCircle2 } from "lucide-react";
import { toast } from "sonner";
import BulkPayslipUploadModal from "./payslips/BulkPayslipUploadModal";
import PayslipDetailsModal from "./PayslipDetailsModal";
import PayslipPdfVerificationModal from "./PayslipPdfVerificationModal";
import CreatePayslipModal from "./CreatePayslipModal";
import MissingPayslipsModal from "./MissingPayslipsModal";
import MissingPayslipsOrganizationsModal from "./MissingPayslipsOrganizationsModal";

// Utility function to format dates as DD/MM/YYYY
function formatDate(dateString: string | null | undefined): string {
  if (!dateString) return "—";
  try {
    const date = new Date(dateString);
    return date.toLocaleDateString('fr-FR', {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric'
    });
  } catch {
    return "—";
  }
}

// Utility function to format currency
function formatCurrency(value: string | number | null | undefined): string {
  if (!value) return "—";
  const num = typeof value === 'string' ? parseFloat(value) : value;
  if (isNaN(num)) return "—";
  return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(num);
}

// Utility function to format period as text (e.g., "Oct. 2025")
function formatPeriodText(periodStart: string | null | undefined): string {
  if (!periodStart) return "—";
  try {
    const date = new Date(periodStart);
    const monthNames = ["Jan.", "Fév.", "Mars", "Avr.", "Mai", "Juin", "Juil.", "Août", "Sept.", "Oct.", "Nov.", "Déc."];
    const month = monthNames[date.getMonth()];
    const year = date.getFullYear();
    return `${month} ${year}`;
  } catch {
    return "—";
  }
}

// Utility function to format employee name
function formatEmployeeName(payslip: { cddu_contracts?: any }): string {
  const contract = payslip.cddu_contracts;
  if (!contract) return "—";
  
  // Priorité : utiliser salaries.salarie si disponible
  if (contract.salaries?.salarie) {
    return contract.salaries.salarie;
  }
  
  // Construire depuis nom + prénom
  if (contract.salaries?.nom || contract.salaries?.prenom) {
    const nom = (contract.salaries.nom || '').toUpperCase().trim();
    const prenom = (contract.salaries.prenom || '').trim();
    return [nom, prenom].filter(Boolean).join(' ');
  }
  
  // Fallback : utiliser employee_name
  if (contract.employee_name) {
    const parts = contract.employee_name.trim().split(' ');
    if (parts.length >= 2) {
      const prenom = parts[0];
      const nom = parts.slice(1).join(' ');
      return `${nom.toUpperCase()} ${prenom}`;
    }
    return contract.employee_name;
  }
  
  return "—";
}

// Utility function to extract last name for sorting
function getLastName(payslip: { cddu_contracts?: any }): string {
  const contract = payslip.cddu_contracts;
  if (!contract) return "";
  
  if (contract.salaries?.nom) {
    return contract.salaries.nom.toUpperCase();
  }
  
  if (contract.employee_name) {
    const parts = contract.employee_name.trim().split(' ');
    if (parts.length >= 2) {
      return parts.slice(1).join(' ');
    }
    return contract.employee_name;
  }
  
  return "";
}

type Payslip = {
  id: string;
  contract_id: string;
  period_start?: string | null;
  period_end?: string | null;
  period_month?: string | null;
  pay_number?: number | null;
  pay_date?: string | null;
  gross_amount?: string | number | null;
  net_amount?: string | number | null;
  net_after_withholding?: string | number | null;
  employer_cost?: string | number | null;
  processed?: boolean | null;
  aem_status?: string | null;
  transfer_done?: boolean | null;
  organization_id?: string | null;
  storage_path?: string | null;
  created_at?: string | null;
  cddu_contracts?: {
    id: string;
    contract_number?: string | null;
    employee_name?: string | null;
    employee_id?: string | null;
    structure?: string | null;
    type_de_contrat?: string | null;
    org_id?: string | null;
    salaries?: {
      salarie?: string | null;
      nom?: string | null;
      prenom?: string | null;
    } | null;
    organizations?: {
      organization_details?: {
        code_employeur?: string | null;
      } | null;
    } | null;
  } | null;
};

export default function PayslipsGrid({ initialData, activeOrgId }: { initialData: Payslip[]; activeOrgId?: string | null }) {
  const [rows, setRows] = useState<Payslip[]>(initialData || []);
  const [showRaw, setShowRaw] = useState(false);
  const [loading, setLoading] = useState(false);
  
  // Selection state
  const [selectedPayslipIds, setSelectedPayslipIds] = useState<Set<string>>(new Set());
  
  // Key for localStorage
  const FILTERS_STORAGE_KEY = 'staff-payslips-filters';
  
  // Helper functions for localStorage
  const saveFiltersToStorage = (filters: any) => {
    try {
      localStorage.setItem(FILTERS_STORAGE_KEY, JSON.stringify(filters));
    } catch (error) {
      console.warn('Failed to save filters to localStorage:', error);
    }
  };
  
  const loadFiltersFromStorage = () => {
    try {
      const saved = localStorage.getItem(FILTERS_STORAGE_KEY);
      return saved ? JSON.parse(saved) : null;
    } catch (error) {
      console.warn('Failed to load filters from localStorage:', error);
      return null;
    }
  };

  // Load saved filters or use defaults
  const savedFilters = loadFiltersFromStorage();
  
  // filters / sorting / pagination - with localStorage persistence
  const [q, setQ] = useState(savedFilters?.q || "");
  const [structureFilter, setStructureFilter] = useState<string | null>(savedFilters?.structureFilter || null);
  const [typeFilter, setTypeFilter] = useState<string | null>(savedFilters?.typeFilter || null);
  const [processedFilter, setProcessedFilter] = useState<string | null>(savedFilters?.processedFilter || null);
  const [transferFilter, setTransferFilter] = useState<string | null>(savedFilters?.transferFilter || null);
  const [aemFilter, setAemFilter] = useState<string | null>(savedFilters?.aemFilter || null);
  const [periodFrom, setPeriodFrom] = useState<string | null>(savedFilters?.periodFrom || null);
  const [periodTo, setPeriodTo] = useState<string | null>(savedFilters?.periodTo || null);
  const [sortField, setSortField] = useState<string>(savedFilters?.sortField || "period_start");
  const [sortOrder, setSortOrder] = useState<'asc'|'desc'>(savedFilters?.sortOrder || 'desc');
  const [page, setPage] = useState(0);
  const [limit, setLimit] = useState(50);
  const [showFilters, setShowFilters] = useState(savedFilters?.showFilters || false);
  const totalCountRef = useRef<number | null>(null);

  // Selection helpers
  const selectedPayslips = rows.filter(payslip => selectedPayslipIds.has(payslip.id));
  const isAllSelected = rows.length > 0 && selectedPayslipIds.size === rows.length;
  const isPartiallySelected = selectedPayslipIds.size > 0 && selectedPayslipIds.size < rows.length;

  // Modal states
  const [showProcessedModal, setShowProcessedModal] = useState(false);
  const [showTransferModal, setShowTransferModal] = useState(false);
  const [showAemModal, setShowAemModal] = useState(false);
  const [showActionMenu, setShowActionMenu] = useState(false);
  const [showDeleteModal, setShowDeleteModal] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [showBulkUploadModal, setShowBulkUploadModal] = useState(false);
  const [showDetailsModal, setShowDetailsModal] = useState(false);
  const [showCreateModal, setShowCreateModal] = useState(false);
  const [payslipDetailsIds, setPayslipDetailsIds] = useState<string[]>([]);
  const [showPdfVerificationModal, setShowPdfVerificationModal] = useState(false);
  const [payslipsPdfs, setPayslipsPdfs] = useState<Array<{
    id: string;
    contractNumber?: string;
    employeeName?: string;
    pdfUrl?: string;
    hasError: boolean;
    errorMessage?: string;
  }>>([]);
  const [isLoadingPdfs, setIsLoadingPdfs] = useState(false);
  
  // Stats for missing payslips
  const [missingPayslipsCount, setMissingPayslipsCount] = useState<number | null>(null);
  const [missingOrganizationsCount, setMissingOrganizationsCount] = useState<number | null>(null);
  const [totalMissingContracts, setTotalMissingContracts] = useState<number | null>(null);
  const [isLoadingStats, setIsLoadingStats] = useState(false);
  const [showMissingPayslipsModal, setShowMissingPayslipsModal] = useState(false);
  const [showMissingOrganizationsModal, setShowMissingOrganizationsModal] = useState(false);
  const [preselectedContractId, setPreselectedContractId] = useState<string | null>(null);
  const isFirstRender = useRef(true);

  // Save filters to localStorage whenever they change
  useEffect(() => {
    const filters = {
      q,
      structureFilter,
      typeFilter,
      processedFilter,
      transferFilter,
      aemFilter,
      periodFrom,
      periodTo,
      sortField,
      sortOrder,
      showFilters
    };
    saveFiltersToStorage(filters);
  }, [q, structureFilter, typeFilter, processedFilter, transferFilter, aemFilter, periodFrom, periodTo, sortField, sortOrder, showFilters]);

  // Fetch initial au montage du composant
  useEffect(() => {
    fetchServer(0);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Handler pour mettre à jour une paie après édition
  const handlePayslipUpdated = (updatedPayslip: any) => {
    setRows((currentRows) =>
      currentRows.map((row) =>
        row.id === updatedPayslip.id ? { ...row, ...updatedPayslip } : row
      )
    );
  };

  // Fonction pour vérifier les PDFs des fiches de paie sélectionnées
  const verifySelectedPdfs = async () => {
    if (selectedPayslipIds.size === 0) {
      toast.error("Aucune fiche de paie sélectionnée");
      return;
    }

    const payslipIds = Array.from(selectedPayslipIds);
    
    // Ouvrir le modal et commencer le chargement
    setShowPdfVerificationModal(true);
    setIsLoadingPdfs(true);
    setPayslipsPdfs([]);

    try {
      // Récupérer les URLs des PDFs pour chaque fiche de paie
      const pdfPromises = payslipIds.map(async (payslipId) => {
        const payslip = rows.find(r => r.id === payslipId);
        
        try {
          // Si pas de storage_path, retourner une erreur
          if (!payslip?.storage_path) {
            return {
              id: payslipId,
              contractNumber: payslip?.cddu_contracts?.contract_number || undefined,
              employeeName: formatEmployeeName(payslip as any),
              pdfUrl: undefined,
              hasError: true,
              errorMessage: 'PDF non uploadé'
            };
          }

          // Générer l'URL presignée
          const response = await fetch('/api/s3-presigned', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ key: payslip.storage_path })
          });
          
          if (response.ok) {
            const result = await response.json();
            return {
              id: payslipId,
              contractNumber: payslip?.cddu_contracts?.contract_number || undefined,
              employeeName: formatEmployeeName(payslip as any),
              pdfUrl: result.url,
              hasError: false
            };
          } else {
            const errorData = await response.json();
            return {
              id: payslipId,
              contractNumber: payslip?.cddu_contracts?.contract_number || undefined,
              employeeName: formatEmployeeName(payslip as any),
              pdfUrl: undefined,
              hasError: true,
              errorMessage: errorData.error || 'PDF non trouvé'
            };
          }
        } catch (error) {
          return {
            id: payslipId,
            contractNumber: payslip?.cddu_contracts?.contract_number || undefined,
            employeeName: formatEmployeeName(payslip as any),
            pdfUrl: undefined,
            hasError: true,
            errorMessage: 'Erreur de réseau'
          };
        }
      });

      const pdfs = await Promise.all(pdfPromises);
      setPayslipsPdfs(pdfs);
      
      const successCount = pdfs.filter(pdf => !pdf.hasError).length;
      const errorCount = pdfs.filter(pdf => pdf.hasError).length;
      
      if (successCount > 0) {
        toast.success(`${successCount} PDF${successCount > 1 ? 's' : ''} chargé${successCount > 1 ? 's' : ''}`);
      }
      if (errorCount > 0) {
        toast.warning(`${errorCount} PDF${errorCount > 1 ? 's' : ''} non disponible${errorCount > 1 ? 's' : ''}`);
      }

    } catch (error) {
      console.error("Erreur lors du chargement des PDFs:", error);
      toast.error("Erreur lors du chargement des PDFs");
    } finally {
      setIsLoadingPdfs(false);
    }
  };

  // Fonction pour fermer le modal de vérification PDF
  const closePdfVerificationModal = () => {
    setShowPdfVerificationModal(false);
    setPayslipsPdfs([]);
    setIsLoadingPdfs(false);
  };

  // Fetch missing payslips statistics when structure and period filters change
  useEffect(() => {
    const fetchMissingStats = async () => {
      if (!periodFrom || !periodTo) {
        setMissingPayslipsCount(null);
        setMissingOrganizationsCount(null);
        setTotalMissingContracts(null);
        return;
      }

      setIsLoadingStats(true);
      try {
        if (structureFilter) {
          // Si une organisation est sélectionnée
          setMissingOrganizationsCount(null);
          setTotalMissingContracts(null);
          
          const params = new URLSearchParams({
            structure: structureFilter,
            period_from: periodFrom,
            period_to: periodTo,
          });

          const response = await fetch(`/api/staff/payslips/missing-stats?${params}`);
          const data = await response.json();

          if (!response.ok) {
            console.error("Error fetching missing stats:", data.error);
            setMissingPayslipsCount(null);
            return;
          }

          setMissingPayslipsCount(data.missing_count || 0);
        } else {
          // Si "Toutes structures"
          setMissingPayslipsCount(null);
          
          const params = new URLSearchParams({
            period_from: periodFrom,
            period_to: periodTo,
          });

          const response = await fetch(`/api/staff/payslips/missing-organizations?${params}`);
          const data = await response.json();

          if (!response.ok) {
            console.error("Error fetching missing organizations:", data.error);
            setMissingOrganizationsCount(null);
            setTotalMissingContracts(null);
            return;
          }

          setMissingOrganizationsCount(data.total_organizations || 0);
          setTotalMissingContracts(data.total_missing_contracts || 0);
        }
      } catch (error) {
        console.error("Error fetching missing stats:", error);
        setMissingPayslipsCount(null);
        setMissingOrganizationsCount(null);
        setTotalMissingContracts(null);
      } finally {
        setIsLoadingStats(false);
      }
    };

    fetchMissingStats();
  }, [structureFilter, periodFrom, periodTo]);

  // Create a callback ref to refetch stats (for use in realtime subscription)
  const refetchStatsRef = useRef<(() => void) | undefined>(undefined);
  useEffect(() => {
    refetchStatsRef.current = async () => {
      if (!structureFilter || !periodFrom || !periodTo) return;
      
      try {
        const params = new URLSearchParams({
          structure: structureFilter,
          period_from: periodFrom,
          period_to: periodTo,
        });

        const response = await fetch(`/api/staff/payslips/missing-stats?${params}`);
        const data = await response.json();

        if (response.ok) {
          setMissingPayslipsCount(data.missing_count || 0);
        }
      } catch (error) {
        console.error("Error refetching missing stats:", error);
      }
    };
  }, [structureFilter, periodFrom, periodTo]);

  // Realtime subscription: listen to INSERT / UPDATE / DELETE on payslips
  useEffect(() => {
    try {
      console.log("PayslipsGrid initialData (client):", Array.isArray(initialData) ? initialData.length : typeof initialData, initialData?.slice?.(0, 3));
    } catch (err) {
      console.log("PayslipsGrid initialData (client) - could not log:", err);
    }

    let channel: any = null;
    let mounted = true;

    (async () => {
      try {
        channel = supabase.channel("public:payslips");
        channel.on(
          "postgres_changes",
          { event: "*", schema: "public", table: "payslips" },
          (payload: any) => {
            try {
              const event = payload.event || payload.eventType || payload.type;
              const record = payload.new ?? payload.record ?? payload.payload ?? payload;

              if (event === "INSERT") {
                const newRec = record as Payslip;
                setRows((rs) => {
                  if (rs.find((r) => r.id === newRec.id)) return rs;
                  return [newRec, ...rs];
                });
                // Refetch stats when a new payslip is created
                refetchStatsRef.current?.();
              } else if (event === "UPDATE") {
                setRows((rs) => rs.map((r) => (r.id === record.id ? { ...r, ...(record as Payslip) } : r)));
              } else if (event === "DELETE") {
                const id = record?.id ?? payload.old?.id;
                if (id) setRows((rs) => rs.filter((r) => r.id !== id));
                // Refetch stats when a payslip is deleted
                refetchStatsRef.current?.();
              }
            } catch (err) {
              console.error("Realtime handler error", err);
            }
          }
        );

        const sub = await channel.subscribe();
        if (!mounted) return;
        if (sub && (sub.status === "timed_out" || sub.status === "closed" || sub?.error)) {
          console.warn("Realtime subscribe returned unexpected status", sub);
        }
      } catch (err: any) {
        console.warn("Realtime subscription failed for public.payslips — falling back to polling.", err?.message ?? err);
      }
    })();

    return () => {
      mounted = false;
      try {
        if (channel) {
          // @ts-ignore
          if (supabase.removeChannel) supabase.removeChannel(channel);
          else channel.unsubscribe && channel.unsubscribe();
        }
      } catch (err) {
        console.warn("Error unsubscribing realtime channel", err);
      }
    };
  }, []);

  // Helper: fetch server-side with current filters
  async function fetchServer(pageIndex = 0) {
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (q) params.set('q', q);
      if (structureFilter) params.set('structure', structureFilter);
      if (typeFilter) params.set('type_de_contrat', typeFilter);
      if (processedFilter) params.set('processed', processedFilter);
      if (transferFilter) params.set('transfer_done', transferFilter);
      if (aemFilter) params.set('aem_status', aemFilter);
      if (periodFrom) params.set('period_from', periodFrom);
      if (periodTo) params.set('period_to', periodTo);
      params.set('sort', sortField);
      params.set('order', sortOrder === 'asc' ? 'asc' : 'desc');
      params.set('limit', String(limit));
      params.set('offset', String(pageIndex * limit));

      const res = await fetch(`/api/staff/payslips/search?${params.toString()}`);
      if (!res.ok) throw new Error('Search failed');
      const j = await res.json();
      totalCountRef.current = j.count ?? (j.rows ? j.rows.length : 0);
      setRows(j.rows ?? []);
      setPage(pageIndex);
    } catch (err) {
      console.error('Search error', err);
    } finally {
      setLoading(false);
    }
  }

  // Manual refresh function for the refresh button
  const handleRefresh = () => {
    fetchServer(0);
  };

  // Reset selection when data changes
  useEffect(() => {
    setSelectedPayslipIds(new Set());
  }, [rows]);

  // Client-side sorting function
  const sortPayslipsLocally = (payslips: Payslip[], field: string, order: 'asc' | 'desc'): Payslip[] => {
    return [...payslips].sort((a, b) => {
      let valueA: any;
      let valueB: any;

      switch (field) {
        case 'employee_name':
          valueA = getLastName(a);
          valueB = getLastName(b);
          break;
        case 'period_start':
        case 'period_end':
        case 'pay_date':
        case 'created_at':
          valueA = a[field as keyof Payslip] ? new Date(a[field as keyof Payslip] as string) : new Date(0);
          valueB = b[field as keyof Payslip] ? new Date(b[field as keyof Payslip] as string) : new Date(0);
          break;
        case 'pay_number':
        case 'gross_amount':
        case 'net_after_withholding':
          valueA = Number(a[field as keyof Payslip]) || 0;
          valueB = Number(b[field as keyof Payslip]) || 0;
          break;
        case 'contract_number':
          valueA = a.cddu_contracts?.contract_number || '';
          valueB = b.cddu_contracts?.contract_number || '';
          break;
        case 'structure':
          valueA = a.cddu_contracts?.structure || '';
          valueB = b.cddu_contracts?.structure || '';
          break;
        default:
          valueA = a[field as keyof Payslip] || '';
          valueB = b[field as keyof Payslip] || '';
      }

      if (typeof valueA === 'string') valueA = valueA.toLowerCase();
      if (typeof valueB === 'string') valueB = valueB.toLowerCase();

      if (valueA < valueB) return order === 'asc' ? -1 : 1;
      if (valueA > valueB) return order === 'asc' ? 1 : -1;
      return 0;
    });
  };

  // Apply local sorting when using initial data
  const sortedRows = useMemo(() => {
    const noFilters = !q && !structureFilter && !typeFilter && !processedFilter && !transferFilter && !aemFilter && !periodFrom && !periodTo;
    
    if (noFilters) {
      return sortPayslipsLocally(rows, sortField, sortOrder);
    }
    
    return rows;
  }, [rows, sortField, sortOrder, q, structureFilter, typeFilter, processedFilter, transferFilter, aemFilter, periodFrom, periodTo]);

  // Selection functions
  const toggleSelectAll = () => {
    if (isAllSelected) {
      setSelectedPayslipIds(new Set());
    } else {
      setSelectedPayslipIds(new Set(sortedRows.map(r => r.id)));
    }
  };

  const toggleSelectPayslip = (payslipId: string) => {
    setSelectedPayslipIds(prev => {
      const newSet = new Set(prev);
      if (newSet.has(payslipId)) {
        newSet.delete(payslipId);
      } else {
        newSet.add(payslipId);
      }
      return newSet;
    });
  };

  // Debounce searches when filters change
  useEffect(() => {
    // Skip le premier rendu car le fetch initial est géré par un autre useEffect
    if (isFirstRender.current) {
      isFirstRender.current = false;
      return;
    }

    const t = setTimeout(() => fetchServer(0), 300);
    return () => clearTimeout(t);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [q, structureFilter, typeFilter, processedFilter, transferFilter, aemFilter, periodFrom, periodTo, sortField, sortOrder, limit]);

  // derive options from initialData for simple selects
  const structures = useMemo(() => {
    const uniqueStructures = Array.from(new Set((initialData || []).map((r) => r.cddu_contracts?.structure).filter(Boolean) as string[]));
    return uniqueStructures.sort((a, b) => a.localeCompare(b, 'fr')).slice(0, 50);
  }, [initialData]);
  
  const aemStatuses = useMemo(() => Array.from(new Set((initialData || []).map((r) => r.aem_status).filter(Boolean) as string[])).slice(0, 50), [initialData]);

  return (
    <div className="relative">
      {/* Filters */}
      <div className="mb-3">
        {/* Ligne du haut: recherche + bouton filtres */}
        <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-3">
          <div className="flex-1">
            <input 
              value={q} 
              onChange={(e) => setQ(e.target.value)} 
              placeholder="Recherche (n° contrat, salarié)" 
              className="w-full rounded border px-2 py-1 text-sm" 
            />
          </div>
          <div className="flex items-center gap-2">
            {/* Filtres rapides toujours visibles */}
            <select 
              value={structureFilter ?? ""} 
              onChange={(e) => {
                const value = e.target.value || null;
                setStructureFilter(value);
                // Note: structureFilter est un nom de structure (string), pas un UUID
                // On ne synchronise pas avec le store global ici car il attend des UUIDs
              }} 
              className="rounded border px-2 py-1 text-sm"
            >
              <option value="">Toutes structures</option>
              {structures.map((s) => (<option key={s} value={s}>{s}</option>))}
            </select>
            <select value={typeFilter ?? ""} onChange={(e) => setTypeFilter(e.target.value || null)} className="rounded border px-2 py-1 text-sm">
              <option value="">Tous types</option>
              <option value="CDD d'usage">CDDU</option>
              <option value="RG">RG (CDD/CDI droit commun)</option>
            </select>
            
            <button 
              onClick={() => setShowFilters(!showFilters)}
              className="inline-flex items-center gap-1 text-sm text-blue-600 hover:text-blue-800 px-2 py-1 rounded border"
            >
              {showFilters ? "Masquer" : "Plus de"} filtres
            </button>
            
            <button 
              onClick={handleRefresh}
              disabled={loading}
              className="inline-flex items-center gap-1 text-sm text-emerald-600 hover:text-emerald-800 px-2 py-1 rounded border disabled:opacity-50 disabled:cursor-not-allowed"
              title="Actualiser les données"
            >
              <RefreshCw className={`w-3 h-3 ${loading ? 'animate-spin' : ''}`} />
              Actualiser
            </button>
            
            <button 
              onClick={() => setShowCreateModal(true)}
              className="inline-flex items-center gap-1 text-sm text-white bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded border border-blue-600"
              title="Créer une nouvelle fiche de paie"
            >
              <Plus className="w-4 h-4" />
              Créer une paie
            </button>
            
            <button 
              className="rounded border px-3 py-1 text-sm" 
              onClick={() => { 
                setQ(''); 
                setStructureFilter(null); 
                setTypeFilter(null);
                setProcessedFilter(null);
                setTransferFilter(null);
                setAemFilter(null);
                setPeriodFrom(null); 
                setPeriodTo(null); 
                setSortField('period_start'); 
                setSortOrder('desc'); 
                setRows(initialData || []); 
              }}
            >
              Réinitialiser
            </button>
          </div>
        </div>

        {/* Filtres avancés (masquables) */}
        {showFilters && (
          <div className="border rounded-lg p-4 bg-slate-50">
            <div className="grid grid-cols-1 md:grid-cols-5 gap-4">
              {/* Filtre État de traitement */}
              <div>
                <label className="block text-sm font-medium text-slate-700 mb-2">
                  État de traitement
                </label>
                <select
                  value={processedFilter ?? ""}
                  onChange={(e) => setProcessedFilter(e.target.value || null)}
                  className="w-full px-3 py-2 border rounded-lg bg-white text-sm"
                >
                  <option value="">Tous</option>
                  <option value="true">Traité</option>
                  <option value="false">Non traité</option>
                </select>
              </div>

              {/* Filtre État de virement */}
              <div>
                <label className="block text-sm font-medium text-slate-700 mb-2">
                  État de virement
                </label>
                <select
                  value={transferFilter ?? ""}
                  onChange={(e) => setTransferFilter(e.target.value || null)}
                  className="w-full px-3 py-2 border rounded-lg bg-white text-sm"
                >
                  <option value="">Tous</option>
                  <option value="true">Virement effectué</option>
                  <option value="false">Virement en attente</option>
                </select>
              </div>

              {/* Filtre AEM */}
              <div>
                <label className="block text-sm font-medium text-slate-700 mb-2">
                  AEM
                </label>
                <select
                  value={aemFilter ?? ""}
                  onChange={(e) => setAemFilter(e.target.value || null)}
                  className="w-full px-3 py-2 border rounded-lg bg-white text-sm"
                >
                  <option value="">Tous les états</option>
                  {aemStatuses.map((status) => (
                    <option key={status} value={status}>{status}</option>
                  ))}
                </select>
              </div>

              {/* Filtre période - De */}
              <div>
                <label className="block text-sm font-medium text-slate-700 mb-2">
                  Période - De
                </label>
                <input
                  type="date"
                  value={periodFrom ?? ""}
                  onChange={(e) => setPeriodFrom(e.target.value || null)}
                  className="w-full px-3 py-2 border rounded-lg bg-white text-sm"
                />
              </div>

              {/* Filtre période - À */}
              <div>
                <label className="block text-sm font-medium text-slate-700 mb-2">
                  Période - À
                </label>
                <input
                  type="date"
                  value={periodTo ?? ""}
                  onChange={(e) => setPeriodTo(e.target.value || null)}
                  className="w-full px-3 py-2 border rounded-lg bg-white text-sm"
                />
              </div>
            </div>
          </div>
        )}

        {/* Card showing missing payslips statistics */}
        {periodFrom && periodTo && (structureFilter || (!structureFilter && missingOrganizationsCount !== null)) && (
          <div className={`mt-4 p-4 border rounded-lg ${
            (structureFilter ? missingPayslipsCount : missingOrganizationsCount) === 0 
              ? 'bg-emerald-50 border-emerald-200' 
              : 'bg-amber-50 border-amber-200'
          }`}>
            {isLoadingStats ? (
              <div className="flex items-center gap-2 text-sm text-amber-800">
                <div className="animate-spin rounded-full h-4 w-4 border-2 border-amber-600 border-t-transparent"></div>
                <span>Calcul en cours...</span>
              </div>
            ) : structureFilter && missingPayslipsCount !== null ? (
              <div className="flex items-center justify-between gap-3">
                <div className="flex items-start gap-3">
                  <div className="flex-shrink-0 mt-0.5">
                    {missingPayslipsCount === 0 ? (
                      <CheckCircle2 className="w-5 h-5 text-emerald-600" />
                    ) : (
                      <svg className="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                      </svg>
                    )}
                  </div>
                  <p className={`text-sm font-medium ${
                    missingPayslipsCount === 0 
                      ? 'text-emerald-900' 
                      : 'text-amber-900'
                  }`}>
                    {missingPayslipsCount === 0 ? (
                      <>Tous les contrats de cette période ont au moins une fiche de paie</>
                    ) : (
                      <>{missingPayslipsCount} contrat{missingPayslipsCount > 1 ? 's' : ''} sans fiche de paie pour cette période</>
                    )}
                  </p>
                </div>
                {missingPayslipsCount > 0 && (
                  <button
                    onClick={() => setShowMissingPayslipsModal(true)}
                    className="flex-shrink-0 inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-amber-900 bg-amber-100 hover:bg-amber-200 border border-amber-300 rounded-lg transition-colors"
                  >
                    <Eye className="w-4 h-4" />
                    Voir la liste
                  </button>
                )}
              </div>
            ) : !structureFilter && missingOrganizationsCount !== null ? (
              <div className="flex items-center justify-between gap-3">
                <div className="flex items-start gap-3">
                  <div className="flex-shrink-0 mt-0.5">
                    {missingOrganizationsCount === 0 ? (
                      <CheckCircle2 className="w-5 h-5 text-emerald-600" />
                    ) : (
                      <svg className="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                      </svg>
                    )}
                  </div>
                  <p className={`text-sm font-medium ${
                    missingOrganizationsCount === 0 
                      ? 'text-emerald-900' 
                      : 'text-amber-900'
                  }`}>
                    {missingOrganizationsCount === 0 ? (
                      <>Toutes les organisations ont des fiches de paie pour cette période</>
                    ) : (
                      <>{missingOrganizationsCount} organisation{missingOrganizationsCount > 1 ? 's' : ''} avec {totalMissingContracts} contrat{totalMissingContracts && totalMissingContracts > 1 ? 's' : ''} sans paie</>
                    )}
                  </p>
                </div>
                {missingOrganizationsCount > 0 && (
                  <button
                    onClick={() => setShowMissingOrganizationsModal(true)}
                    className="flex-shrink-0 inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-amber-900 bg-amber-100 hover:bg-amber-200 border border-amber-300 rounded-lg transition-colors"
                  >
                    <Eye className="w-4 h-4" />
                    Voir la liste
                  </button>
                )}
              </div>
            ) : null}
          </div>
        )}
      </div>

      {/* Boutons d'actions groupées */}
      {selectedPayslipIds.size > 0 && (
        <div className="mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg">
          <div className="flex items-center justify-between">
            <span className="text-sm text-blue-800 font-medium">
              {selectedPayslipIds.size} fiche{selectedPayslipIds.size > 1 ? 's' : ''} de paie sélectionnée{selectedPayslipIds.size > 1 ? 's' : ''}
            </span>
            <div className="flex gap-2">
              {/* Menu dropdown pour les actions groupées */}
              <div className="relative">
                <button
                  onClick={() => setShowActionMenu(!showActionMenu)}
                  className="px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors flex items-center gap-1"
                >
                  Action groupée
                  <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                  </svg>
                </button>
                
                {showActionMenu && (
                  <>
                    <div 
                      className="fixed inset-0 z-10" 
                      onClick={() => setShowActionMenu(false)}
                    />
                    <div className="absolute right-0 mt-1 w-48 bg-white rounded-md shadow-lg z-20 border border-gray-200">
                      <div className="py-1">
                        <button
                          onClick={() => {
                            setPayslipDetailsIds(Array.from(selectedPayslipIds));
                            setShowDetailsModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors flex items-center gap-2"
                        >
                          <Eye className="w-4 h-4" />
                          Voir le détail
                        </button>
                        <div className="border-t border-gray-200 my-1"></div>
                        <button
                          onClick={() => {
                            setShowProcessedModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors"
                        >
                          Modifier état traitement
                        </button>
                        <button
                          onClick={() => {
                            setShowTransferModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors"
                        >
                          Modifier état virement
                        </button>
                        <button
                          onClick={() => {
                            setShowAemModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors"
                        >
                          Modifier AEM
                        </button>
                        <button
                          onClick={() => {
                            setShowBulkUploadModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors"
                        >
                          Ajouter documents
                        </button>
                        <button
                          onClick={() => {
                            verifySelectedPdfs();
                            setShowActionMenu(false);
                          }}
                          disabled={isLoadingPdfs}
                          className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors disabled:text-gray-400 disabled:hover:bg-white flex items-center gap-2"
                        >
                          <Eye className="w-4 h-4" />
                          {isLoadingPdfs ? "Chargement..." : "Vérifier PDFs"}
                        </button>
                        <div className="border-t border-gray-200 my-1"></div>
                        <button
                          onClick={() => {
                            setShowDeleteModal(true);
                            setShowActionMenu(false);
                          }}
                          className="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 transition-colors"
                        >
                          Supprimer
                        </button>
                      </div>
                    </div>
                  </>
                )}
              </div>
              
              <button
                onClick={() => setSelectedPayslipIds(new Set())}
                className="px-3 py-1 text-sm bg-gray-500 text-white rounded hover:bg-gray-600 transition-colors"
              >
                Désélectionner tout
              </button>
            </div>
          </div>
        </div>
      )}

      <div className="overflow-auto">
        <table className="w-full text-xs">
          <thead className="bg-slate-50 text-slate-600">
            <tr>
              <th className="text-left px-3 py-2 w-12">
                <input
                  type="checkbox"
                  checked={isAllSelected}
                  ref={(el) => {
                    if (el) el.indeterminate = isPartiallySelected;
                  }}
                  onChange={toggleSelectAll}
                  className="rounded border-gray-300"
                />
              </th>
              <th className="text-left px-3 py-2" title="État traitement">T</th>
              <th className="text-left px-3 py-2" title="État virement">V</th>
              <th className="text-left px-3 py-2" title="AEM">A</th>
              <th className="text-left px-3 py-2 cursor-pointer" onClick={() => { setSortField('contract_number'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                N° contrat {sortField === 'contract_number' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-left px-3 py-2 cursor-pointer" onClick={() => { setSortField('pay_number'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                N° Paie {sortField === 'pay_number' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-left px-3 py-2 cursor-pointer" onClick={() => { setSortField('employee_name'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Salarié {sortField === 'employee_name' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-left px-3 py-2 cursor-pointer" onClick={() => { setSortField('structure'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Structure {sortField === 'structure' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-left px-3 py-2 cursor-pointer whitespace-nowrap" onClick={() => { setSortField('period_start'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Période {sortField === 'period_start' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-right px-3 py-2 cursor-pointer" onClick={() => { setSortField('gross_amount'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Brut {sortField === 'gross_amount' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-right px-3 py-2 cursor-pointer" onClick={() => { setSortField('net_amount'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Net avant PAS {sortField === 'net_amount' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-right px-3 py-2 cursor-pointer" onClick={() => { setSortField('net_after_withholding'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Net à payer {sortField === 'net_after_withholding' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
              <th className="text-right px-3 py-2 cursor-pointer" onClick={() => { setSortField('employer_cost'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
                Coût employeur {sortField === 'employer_cost' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
              </th>
            </tr>
            <tr className="bg-indigo-50 border-t border-slate-200 font-semibold">
              <td className="px-3 py-2" colSpan={9}>
                <span className="text-slate-700">
                  Totaux ({selectedPayslipIds.size > 0 ? `${selectedPayslipIds.size} ligne${selectedPayslipIds.size > 1 ? 's' : ''} sélectionnée${selectedPayslipIds.size > 1 ? 's' : ''}` : `${sortedRows.length} ligne${sortedRows.length > 1 ? 's' : ''}`})
                </span>
              </td>
              <td className="text-right px-3 py-2 text-slate-700">
                {formatCurrency((selectedPayslipIds.size > 0 ? sortedRows.filter(r => selectedPayslipIds.has(r.id)) : sortedRows).reduce((sum, r) => {
                  const val = typeof r.gross_amount === 'string' ? parseFloat(r.gross_amount) : (r.gross_amount || 0);
                  return sum + (isNaN(val) ? 0 : val);
                }, 0))}
              </td>
              <td className="text-right px-3 py-2 text-slate-700">
                {formatCurrency((selectedPayslipIds.size > 0 ? sortedRows.filter(r => selectedPayslipIds.has(r.id)) : sortedRows).reduce((sum, r) => {
                  const val = typeof r.net_amount === 'string' ? parseFloat(r.net_amount) : (r.net_amount || 0);
                  return sum + (isNaN(val) ? 0 : val);
                }, 0))}
              </td>
              <td className="text-right px-3 py-2 text-slate-700">
                {formatCurrency((selectedPayslipIds.size > 0 ? sortedRows.filter(r => selectedPayslipIds.has(r.id)) : sortedRows).reduce((sum, r) => {
                  const val = typeof r.net_after_withholding === 'string' ? parseFloat(r.net_after_withholding) : (r.net_after_withholding || 0);
                  return sum + (isNaN(val) ? 0 : val);
                }, 0))}
              </td>
              <td className="text-right px-3 py-2 text-slate-700">
                {formatCurrency((selectedPayslipIds.size > 0 ? sortedRows.filter(r => selectedPayslipIds.has(r.id)) : sortedRows).reduce((sum, r) => {
                  const val = typeof r.employer_cost === 'string' ? parseFloat(r.employer_cost) : (r.employer_cost || 0);
                  return sum + (isNaN(val) ? 0 : val);
                }, 0))}
              </td>
            </tr>
          </thead>
          <tbody>
            {sortedRows.map((r) => (
              <tr 
                key={r.id} 
                className={`border-t hover:bg-slate-50 ${selectedPayslipIds.has(r.id) ? 'bg-blue-50' : ''}`}
              >
                <td className="px-3 py-2" onClick={(e) => e.stopPropagation()}>
                  <input
                    type="checkbox"
                    checked={selectedPayslipIds.has(r.id)}
                    onChange={() => toggleSelectPayslip(r.id)}
                    className="rounded border-gray-300"
                  />
                </td>
                <td className="px-3 py-2">
                  {r.processed ? (
                    <Check className="w-4 h-4 text-green-600" strokeWidth={3} />
                  ) : (
                    <X className="w-4 h-4 text-orange-600" strokeWidth={3} />
                  )}
                </td>
                <td className="px-3 py-2">
                  {r.transfer_done ? (
                    <Check className="w-4 h-4 text-green-600" strokeWidth={3} />
                  ) : (
                    <X className="w-4 h-4 text-orange-600" strokeWidth={3} />
                  )}
                </td>
                <td className="px-3 py-2">
                  {(() => {
                    // Les contrats RG (CDD de droit commun + CDI) ne sont pas concernés par l'AEM
                    const contractType = r.cddu_contracts?.type_de_contrat;
                    const isRG = contractType === "CDD de droit commun" || contractType === "CDI";
                    
                    if (isRG) {
                      return <span className="text-xs text-slate-400">N/A</span>;
                    }
                    
                    const status = r.aem_status || "À traiter";
                    if (status === "Traité") {
                      return <Check className="w-4 h-4 text-green-600" strokeWidth={3} />;
                    } else {
                      return <X className="w-4 h-4 text-orange-600" strokeWidth={3} />;
                    }
                  })()}
                </td>
                <td 
                  className="px-3 py-2 cursor-pointer hover:text-blue-600"
                  onClick={() => {
                    if (r.contract_id) {
                      window.location.href = `/staff/contrats/${r.contract_id}`;
                    }
                  }}
                >
                  {r.cddu_contracts?.contract_number || "—"}
                </td>
                <td className="px-3 py-2">{r.pay_number ?? "—"}</td>
                <td className="px-3 py-2">{formatEmployeeName(r)}</td>
                <td className="px-3 py-2">
                  {r.cddu_contracts?.organizations?.organization_details?.code_employeur || "—"}
                </td>
                <td className="px-3 py-2 whitespace-nowrap">
                  {formatPeriodText(r.period_start)}
                </td>
                <td className="px-3 py-2 text-right">{formatCurrency(r.gross_amount)}</td>
                <td className="px-3 py-2 text-right">{formatCurrency(r.net_amount)}</td>
                <td className="px-3 py-2 text-right">{formatCurrency(r.net_after_withholding)}</td>
                <td className="px-3 py-2 text-right">{formatCurrency(r.employer_cost)}</td>
              </tr>
            ))}
          </tbody>
        </table>
        {sortedRows.length === 0 && (
          <div className="p-4 text-sm text-slate-600">
            <div>Aucune fiche de paie trouvée.</div>
            <div className="mt-2">
              <button
                className="text-xs underline"
                onClick={() => setShowRaw((s) => !s)}
              >
                {showRaw ? "Cacher le payload" : "Voir le payload reçu"}
              </button>
            </div>
            {showRaw && (
              <pre className="mt-2 max-h-48 overflow-auto text-xs bg-slate-50 p-2 rounded border">{JSON.stringify(initialData, null, 2)}</pre>
            )}
          </div>
        )}
      </div>

      {/* Pagination / info */}
      <div className="mt-3 flex items-center justify-between text-xs text-slate-600">
        <div className="flex items-center gap-3">
          <div>{loading ? 'Chargement…' : `Affichage ${sortedRows.length}${totalCountRef.current ? ` / ${totalCountRef.current}` : ''}`}</div>
          <div className="flex items-center gap-2">
            <label className="text-xs">Afficher :</label>
            <select 
              value={limit} 
              onChange={(e) => setLimit(Number(e.target.value))}
              className="text-xs px-2 py-1 rounded border bg-white"
            >
              <option value={25}>25</option>
              <option value={50}>50</option>
              <option value={100}>100</option>
            </select>
          </div>
        </div>
        <div className="flex items-center gap-2">
          <button className="text-xs px-2 py-1 rounded border" onClick={() => { if (page > 0) fetchServer(page - 1); }}>Préc</button>
          <button className="text-xs px-2 py-1 rounded border" onClick={() => { fetchServer(page + 1); }}>Suiv</button>
        </div>
      </div>

      {/* Modal Action groupée État de traitement */}
      {showProcessedModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 w-full max-w-md">
            <h3 className="text-lg font-semibold mb-4">Action groupée - État de traitement</h3>
            <p className="text-sm text-gray-600 mb-4">
              Modifier l'état de traitement pour {selectedPayslipIds.size} fiche{selectedPayslipIds.size > 1 ? 's' : ''} de paie
            </p>
            <ProcessedActionModal
              selectedPayslips={selectedPayslips}
              onClose={() => setShowProcessedModal(false)}
              onSuccess={(updatedPayslips) => {
                setRows(prev => prev.map(row => {
                  const updated = updatedPayslips.find(u => u.id === row.id);
                  return updated ? { ...row, processed: updated.processed } : row;
                }));
                setShowProcessedModal(false);
                setSelectedPayslipIds(new Set());
              }}
            />
          </div>
        </div>
      )}

      {/* Modal Action groupée État de virement */}
      {showTransferModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 w-full max-w-md">
            <h3 className="text-lg font-semibold mb-4">Action groupée - État de virement</h3>
            <p className="text-sm text-gray-600 mb-4">
              Modifier l'état de virement pour {selectedPayslipIds.size} fiche{selectedPayslipIds.size > 1 ? 's' : ''} de paie
            </p>
            <TransferActionModal
              selectedPayslips={selectedPayslips}
              onClose={() => setShowTransferModal(false)}
              onSuccess={(updatedPayslips) => {
                setRows(prev => prev.map(row => {
                  const updated = updatedPayslips.find(u => u.id === row.id);
                  return updated ? { ...row, transfer_done: updated.transfer_done } : row;
                }));
                setShowTransferModal(false);
                setSelectedPayslipIds(new Set());
              }}
            />
          </div>
        </div>
      )}

      {/* Modal Action groupée AEM */}
      {showAemModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 w-full max-w-md">
            <h3 className="text-lg font-semibold mb-4">Action groupée - AEM</h3>
            <p className="text-sm text-gray-600 mb-4">
              Modifier l'état AEM pour {selectedPayslipIds.size} fiche{selectedPayslipIds.size > 1 ? 's' : ''} de paie
            </p>
            <AemActionModal
              selectedPayslips={selectedPayslips}
              onClose={() => setShowAemModal(false)}
              onSuccess={(updatedPayslips) => {
                setRows(prev => prev.map(row => {
                  const updated = updatedPayslips.find(u => u.id === row.id);
                  return updated ? { ...row, aem_status: updated.aem_status } : row;
                }));
                setShowAemModal(false);
                setSelectedPayslipIds(new Set());
              }}
            />
          </div>
        </div>
      )}

      {/* Modal Confirmation de suppression */}
      {showDeleteModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 w-full max-w-md">
            <h3 className="text-lg font-semibold mb-4 text-red-600">⚠️ Confirmation de suppression</h3>
            <p className="text-sm text-gray-600 mb-4">
              Êtes-vous sûr de vouloir supprimer {selectedPayslipIds.size} fiche{selectedPayslipIds.size > 1 ? 's' : ''} de paie ?
            </p>
            <p className="text-sm text-red-600 font-medium mb-4">
              Cette action est irréversible.
            </p>
            <DeleteActionModal
              selectedPayslips={selectedPayslips}
              onClose={() => setShowDeleteModal(false)}
              onSuccess={() => {
                // Supprimer les payslips de la liste
                setRows(prev => prev.filter(row => !selectedPayslipIds.has(row.id)));
                setShowDeleteModal(false);
                setSelectedPayslipIds(new Set());
                toast.success(`${selectedPayslipIds.size} fiche${selectedPayslipIds.size > 1 ? 's' : ''} de paie supprimée${selectedPayslipIds.size > 1 ? 's' : ''}`);
              }}
              isDeleting={isDeleting}
              setIsDeleting={setIsDeleting}
            />
          </div>
        </div>
      )}

      {/* Modal Upload en masse */}
      {showBulkUploadModal && (
        <BulkPayslipUploadModal
          isOpen={showBulkUploadModal}
          onClose={() => setShowBulkUploadModal(false)}
          payslips={selectedPayslips}
          onSuccess={() => {
            // Rafraîchir les données
            fetchServer(page);
            setSelectedPayslipIds(new Set());
          }}
        />
      )}

      {/* Modal Détails des paies */}
      <PayslipDetailsModal
        isOpen={showDetailsModal}
        onClose={() => setShowDetailsModal(false)}
        payslipIds={payslipDetailsIds}
        payslips={rows}
        onPayslipUpdated={handlePayslipUpdated}
      />

      {/* Modal Créer une paie */}
      <CreatePayslipModal
        isOpen={showCreateModal}
        onClose={() => {
          setShowCreateModal(false);
          setPreselectedContractId(null);
        }}
        onPayslipCreated={() => {
          // Rafraîchir les données
          fetchServer(page);
          // Rafraîchir les stats aussi
          refetchStatsRef.current?.();
        }}
        preselectedContractId={preselectedContractId}
      />

      {/* Modal Liste des contrats sans paie */}
      {showMissingPayslipsModal && structureFilter && periodFrom && periodTo && (
        <MissingPayslipsModal
          isOpen={showMissingPayslipsModal}
          onClose={() => setShowMissingPayslipsModal(false)}
          structureId={structureFilter}
          periodFrom={periodFrom}
          periodTo={periodTo}
          onContractSelect={(contractId) => {
            setPreselectedContractId(contractId);
            setShowCreateModal(true);
          }}
        />
      )}

      {/* Modal Liste des organisations avec contrats sans paie */}
      {showMissingOrganizationsModal && periodFrom && periodTo && (
        <MissingPayslipsOrganizationsModal
          isOpen={showMissingOrganizationsModal}
          onClose={() => setShowMissingOrganizationsModal(false)}
          periodFrom={periodFrom}
          periodTo={periodTo}
          onOrganizationSelect={(orgId) => {
            setStructureFilter(orgId);
            setShowMissingOrganizationsModal(false);
            setShowMissingPayslipsModal(true);
          }}
        />
      )}

      {/* Modal de vérification des PDFs */}
      <PayslipPdfVerificationModal
        isOpen={showPdfVerificationModal}
        onClose={closePdfVerificationModal}
        payslips={payslipsPdfs}
        isLoading={isLoadingPdfs}
      />
    </div>
  );
}

// Modal pour l'action groupée État de traitement
function ProcessedActionModal({ 
  selectedPayslips, 
  onClose, 
  onSuccess 
}: { 
  selectedPayslips: Payslip[]; 
  onClose: () => void; 
  onSuccess: (payslips: { id: string; processed: boolean }[]) => void; 
}) {
  const [newProcessed, setNewProcessed] = useState<string>('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (newProcessed === '') return;
    
    setLoading(true);
    try {
      const response = await fetch('/api/staff/payslips/bulk-update-processed', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          payslipIds: selectedPayslips.map(p => p.id),
          processed: newProcessed === 'true'
        })
      });

      if (!response.ok) throw new Error('Erreur lors de la mise à jour');
      
      const result = await response.json();
      onSuccess(result.payslips);
      toast.success('États de traitement mis à jour');
    } catch (error) {
      console.error('Erreur:', error);
      toast.error('Erreur lors de la mise à jour');
    } finally {
      setLoading(false);
    }
  };

  return (
    <>
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">
            État de traitement
          </label>
          <select
            value={newProcessed}
            onChange={(e) => setNewProcessed(e.target.value)}
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="">Sélectionner un état</option>
            <option value="true">Traité</option>
            <option value="false">À traiter</option>
          </select>
        </div>

        <div className="border rounded-lg p-3 max-h-40 overflow-y-auto">
          <p className="text-sm font-medium text-gray-700 mb-2">Fiches de paie sélectionnées :</p>
          {selectedPayslips.map(payslip => (
            <div key={payslip.id} className="text-sm text-gray-600 py-1">
              {payslip.cddu_contracts?.contract_number || payslip.id} - {formatEmployeeName(payslip)}
            </div>
          ))}
        </div>
      </div>

      <div className="flex justify-end gap-2 mt-6">
        <button
          onClick={onClose}
          className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded hover:bg-gray-50"
          disabled={loading}
        >
          Annuler
        </button>
        <button
          onClick={handleSubmit}
          disabled={newProcessed === '' || loading}
          className="px-4 py-2 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {loading ? 'Mise à jour...' : 'Appliquer'}
        </button>
      </div>
    </>
  );
}

// Modal pour l'état de virement
function TransferActionModal({ 
  selectedPayslips, 
  onClose, 
  onSuccess 
}: { 
  selectedPayslips: Payslip[]; 
  onClose: () => void; 
  onSuccess: (payslips: { id: string; transfer_done: boolean }[]) => void; 
}) {
  const [newTransfer, setNewTransfer] = useState<string>('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (newTransfer === '') return;
    
    setLoading(true);
    try {
      const response = await fetch('/api/staff/payslips/bulk-update-transfer', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          payslipIds: selectedPayslips.map(p => p.id),
          transferDone: newTransfer === 'true'
        })
      });

      if (!response.ok) throw new Error('Erreur lors de la mise à jour');
      
      const result = await response.json();
      onSuccess(result.payslips);
      toast.success('États de virement mis à jour');
    } catch (error) {
      console.error('Erreur:', error);
      toast.error('Erreur lors de la mise à jour');
    } finally {
      setLoading(false);
    }
  };

  return (
    <>
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">
            État de virement
          </label>
          <select
            value={newTransfer}
            onChange={(e) => setNewTransfer(e.target.value)}
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="">Sélectionner un état</option>
            <option value="true">Effectué</option>
            <option value="false">En attente</option>
          </select>
        </div>

        <div className="border rounded-lg p-3 max-h-40 overflow-y-auto">
          <p className="text-sm font-medium text-gray-700 mb-2">Fiches de paie sélectionnées :</p>
          {selectedPayslips.map(payslip => (
            <div key={payslip.id} className="text-sm text-gray-600 py-1">
              {payslip.cddu_contracts?.contract_number || payslip.id} - {formatEmployeeName(payslip)}
            </div>
          ))}
        </div>
      </div>

      <div className="flex justify-end gap-2 mt-6">
        <button
          onClick={onClose}
          className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded hover:bg-gray-50"
          disabled={loading}
        >
          Annuler
        </button>
        <button
          onClick={handleSubmit}
          disabled={newTransfer === '' || loading}
          className="px-4 py-2 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {loading ? 'Mise à jour...' : 'Appliquer'}
        </button>
      </div>
    </>
  );
}

// Modal pour AEM
function AemActionModal({ 
  selectedPayslips, 
  onClose, 
  onSuccess 
}: { 
  selectedPayslips: Payslip[]; 
  onClose: () => void; 
  onSuccess: (payslips: { id: string; aem_status: string }[]) => void; 
}) {
  const [newAem, setNewAem] = useState<string>('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!newAem) return;
    
    setLoading(true);
    try {
      const response = await fetch('/api/staff/payslips/bulk-update-aem', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          payslipIds: selectedPayslips.map(p => p.id),
          aemStatus: newAem
        })
      });

      if (!response.ok) throw new Error('Erreur lors de la mise à jour');
      
      const result = await response.json();
      onSuccess(result.payslips);
      toast.success('États AEM mis à jour');
    } catch (error) {
      console.error('Erreur:', error);
      toast.error('Erreur lors de la mise à jour');
    } finally {
      setLoading(false);
    }
  };

  return (
    <>
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">
            État AEM
          </label>
          <select
            value={newAem}
            onChange={(e) => setNewAem(e.target.value)}
            className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="">Sélectionner un état</option>
            <option value="À traiter">À traiter</option>
            <option value="En cours">En cours</option>
            <option value="Traité">Traité</option>
          </select>
        </div>

        <div className="border rounded-lg p-3 max-h-40 overflow-y-auto">
          <p className="text-sm font-medium text-gray-700 mb-2">Fiches de paie sélectionnées :</p>
          {selectedPayslips.map(payslip => (
            <div key={payslip.id} className="text-sm text-gray-600 py-1">
              {payslip.cddu_contracts?.contract_number || payslip.id} - {formatEmployeeName(payslip)}
            </div>
          ))}
        </div>
      </div>

      <div className="flex justify-end gap-2 mt-6">
        <button
          onClick={onClose}
          className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded hover:bg-gray-50"
          disabled={loading}
        >
          Annuler
        </button>
        <button
          onClick={handleSubmit}
          disabled={!newAem || loading}
          className="px-4 py-2 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {loading ? 'Mise à jour...' : 'Appliquer'}
        </button>
      </div>
    </>
  );
}

// Modal pour la suppression
function DeleteActionModal({ 
  selectedPayslips, 
  onClose, 
  onSuccess,
  isDeleting,
  setIsDeleting
}: { 
  selectedPayslips: Payslip[]; 
  onClose: () => void; 
  onSuccess: () => void; 
  isDeleting: boolean;
  setIsDeleting: (value: boolean) => void;
}) {
  const handleDelete = async () => {
    setIsDeleting(true);
    try {
      const response = await fetch('/api/staff/payslips/bulk-delete', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          payslipIds: selectedPayslips.map(p => p.id)
        })
      });

      if (!response.ok) throw new Error('Erreur lors de la suppression');
      
      const result = await response.json();
      onSuccess();
    } catch (error) {
      console.error('Erreur:', error);
      toast.error('Erreur lors de la suppression');
    } finally {
      setIsDeleting(false);
    }
  };

  return (
    <>
      <div className="space-y-4">
        <div className="border rounded-lg p-3 max-h-40 overflow-y-auto bg-red-50">
          <p className="text-sm font-medium text-gray-700 mb-2">Fiches de paie à supprimer :</p>
          {selectedPayslips.map(payslip => (
            <div key={payslip.id} className="text-sm text-gray-600 py-1">
              {payslip.cddu_contracts?.contract_number || payslip.id} - {formatEmployeeName(payslip)}
            </div>
          ))}
        </div>
      </div>

      <div className="flex justify-end gap-2 mt-6">
        <button
          onClick={onClose}
          className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded hover:bg-gray-50"
          disabled={isDeleting}
        >
          Annuler
        </button>
        <button
          onClick={handleDelete}
          disabled={isDeleting}
          className="px-4 py-2 text-sm bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {isDeleting ? 'Suppression...' : 'Supprimer définitivement'}
        </button>
      </div>
    </>
  );
}
