'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { isAxiosError } from 'axios';
import { format } from 'date-fns';
import { fr } from 'date-fns/locale';
import {
  ChevronLeft,
  ChevronRight,
  ExternalLink,
  FolderOpen,
  Loader2,
  Lock,
  Plus,
  RotateCcw,
  Search,
} from 'lucide-react';
import Link from 'next/link';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { z } from 'zod';

import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { StatutDossierBadge } from '@/components/dossiers/statut-dossier-badge';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import {
  createDossier,
  extractApiErrorMessage,
  fetchMe,
  fetchTousDossiers,
  type AuthUser,
  type Dossier,
  type FiltresDossiers,
  type ListeDossiers,
} from '@/lib/api';
import { cn } from '@/lib/utils';

const PAGE_SIZE_OPTIONS = [10, 25, 50] as const;

const selectClassName =
  'flex h-10 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';

const FILTRES_VIDES: FiltresDossiers = {
  id_cont: '',
  immatriculation: '',
  type_demarche: '',
  date_debut: '',
  date_fin: '',
};

const createDossierSchema = z.object({
  nom: z.string().min(1, 'Le nom est requis').max(255),
  description: z.string().max(1000).optional(),
  immatriculation: z.string().max(12).optional(),
  type_demarche: z.string().max(255).optional(),
});

type CreateDossierFormValues = z.infer<typeof createDossierSchema>;

function nomClient(dossier: Dossier): string | null {
  return (
    dossier.conteneur?.libelle ??
    dossier.conteneur?.reference_externe ??
    dossier.conteneur?.id_cont ??
    dossier.id_cont ??
    null
  );
}

export function ListeDossiersPanel() {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

  // Le conteneur peut être imposé par l'URL (lien « Voir » depuis le coffre-fort).
  const idContUrl = searchParams.get('id_cont') ?? '';

  const [user, setUser] = useState<AuthUser | null>(null);
  const [isUserLoading, setIsUserLoading] = useState(true);
  const [dossiers, setDossiers] = useState<Dossier[]>([]);
  const [optionsFiltres, setOptionsFiltres] = useState<
    ListeDossiers['filtres']
  >({ clients: [], demarches: [] });
  const [isLoading, setIsLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);

  // Saisie en cours dans le formulaire, distincte des filtres réellement appliqués.
  const [saisie, setSaisie] = useState<FiltresDossiers>({
    ...FILTRES_VIDES,
    id_cont: idContUrl,
  });
  const [filtresAppliques, setFiltresAppliques] = useState<FiltresDossiers>({
    ...FILTRES_VIDES,
    id_cont: idContUrl,
  });

  const [dialogOpen, setDialogOpen] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<CreateDossierFormValues>({
    resolver: zodResolver(createDossierSchema),
    defaultValues: {
      nom: '',
      description: '',
      immatriculation: '',
      type_demarche: '',
    },
  });

  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState<(typeof PAGE_SIZE_OPTIONS)[number]>(
    PAGE_SIZE_OPTIONS[0],
  );

  const chargerDossiers = useCallback(async (filtres: FiltresDossiers) => {
    setIsLoading(true);
    setLoadError(null);

    try {
      const resultat = await fetchTousDossiers(filtres);
      setDossiers(resultat.dossiers);
      setOptionsFiltres(resultat.filtres);
    } catch (error) {
      if (isAxiosError(error) && error.response?.status === 401) {
        setLoadError('Session expirée. Veuillez vous reconnecter.');
      } else {
        setLoadError(
          extractApiErrorMessage(error, 'Impossible de charger les dossiers.'),
        );
      }
    } finally {
      setIsLoading(false);
    }
  }, []);

  // §5.6.2 : l'UTI-F administre les conteneurs mais n'accède jamais à leur
  // contenu ; l'UTI-G n'a aucune attribution sur les dossiers (§5.6.1).
  const peutListerDossiers = user?.role_ccfn === 'UTI-S';

  useEffect(() => {
    let cancelled = false;

    fetchMe()
      .then((me) => {
        if (!cancelled) {
          setUser(me);
        }
      })
      .catch(() => {
        if (!cancelled) {
          setLoadError('Session expirée. Veuillez vous reconnecter.');
        }
      })
      .finally(() => {
        if (!cancelled) {
          setIsUserLoading(false);
        }
      });

    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    if (!peutListerDossiers) {
      return;
    }

    void chargerDossiers(filtresAppliques);
  }, [chargerDossiers, filtresAppliques, peutListerDossiers]);

  useEffect(() => {
    setSaisie((current) =>
      current.id_cont === idContUrl ? current : { ...current, id_cont: idContUrl },
    );
    setFiltresAppliques((current) =>
      current.id_cont === idContUrl ? current : { ...current, id_cont: idContUrl },
    );
  }, [idContUrl]);

  const totalPages = Math.max(1, Math.ceil(dossiers.length / pageSize));
  const currentPage = Math.min(page, totalPages);

  const dossiersPagines = useMemo(() => {
    const debut = (currentPage - 1) * pageSize;
    return dossiers.slice(debut, debut + pageSize);
  }, [dossiers, currentPage, pageSize]);

  const rangeStart = dossiers.length === 0 ? 0 : (currentPage - 1) * pageSize + 1;
  const rangeEnd = Math.min(currentPage * pageSize, dossiers.length);

  useEffect(() => {
    setPage(1);
  }, [filtresAppliques, pageSize]);

  const aDesFiltres = Object.values(filtresAppliques).some(
    (valeur) => valeur !== undefined && valeur !== '',
  );

  // Le conteneur sélectionné reste dans l'URL pour que la vue soit partageable.
  const synchroniserUrl = useCallback(
    (idCont: string) => {
      if (idCont === idContUrl) {
        return;
      }

      router.replace(idCont ? `${pathname}?id_cont=${idCont}` : pathname, {
        scroll: false,
      });
    },
    [idContUrl, pathname, router],
  );

  function onSubmitFiltres(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setFiltresAppliques(saisie);
    synchroniserUrl(saisie.id_cont ?? '');
  }

  function onReinitialiser() {
    setSaisie(FILTRES_VIDES);
    setFiltresAppliques(FILTRES_VIDES);
    synchroniserUrl('');
  }

  const clientSelectionne = optionsFiltres.clients.find(
    (client) => client.id_cont === filtresAppliques.id_cont,
  );

  const onCreateDossier = async (values: CreateDossierFormValues) => {
    const idCont = filtresAppliques.id_cont;

    if (!idCont) {
      return;
    }

    try {
      setSubmitError(null);

      await createDossier(idCont, {
        nom: values.nom.trim(),
        description: values.description?.trim() || undefined,
        immatriculation: values.immatriculation?.trim() || undefined,
        type_demarche: values.type_demarche?.trim() || undefined,
      });

      reset();
      setDialogOpen(false);
      await chargerDossiers(filtresAppliques);
    } catch (error) {
      setSubmitError(
        extractApiErrorMessage(error, 'Impossible de créer le dossier.'),
      );
    }
  };

  if (isUserLoading) {
    return (
      <div className="flex items-center justify-center gap-2 py-16 text-sm text-muted-foreground">
        <Loader2 className="h-5 w-5 animate-spin" />
        Chargement…
      </div>
    );
  }

  if (!peutListerDossiers) {
    return (
      <Card>
        <CardContent className="flex flex-col items-center gap-3 py-12 text-center">
          <Lock className="h-10 w-10 text-muted-foreground/60" />
          <div>
            <p className="font-medium">Liste des dossiers non accessible</p>
            <p className="mt-1 max-w-md text-sm text-muted-foreground">
              {loadError ??
                `Votre profil (${user?.role_ccfn ?? '—'}) administre le coffre-fort mais n'accède pas aux dossiers qu'il conserve. Connectez-vous avec un compte UTI-S pour consulter la liste des dossiers.`}
            </p>
          </div>
        </CardContent>
      </Card>
    );
  }

  return (
    <>
      <div className="mb-8 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex items-center gap-3">
          <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10">
            <FolderOpen className="h-6 w-6 text-primary" />
          </div>
          <div>
            <h1 className="text-2xl font-bold tracking-tight">
              Liste des dossiers
            </h1>
            <p className="text-sm text-muted-foreground">
              {filtresAppliques.id_cont
                ? `Dossiers du client ${clientSelectionne?.libelle ?? filtresAppliques.id_cont}`
                : "Tous les dossiers d'archivage, tous clients confondus"}
            </p>
          </div>
        </div>

        {filtresAppliques.id_cont ? (
          <Button onClick={() => setDialogOpen(true)}>
            <Plus className="h-4 w-4" />
            Nouveau dossier
          </Button>
        ) : null}
      </div>

      <Card>
        <CardHeader className="gap-4 border-b pb-6">
          <div>
            <CardTitle className="text-base">Dossiers</CardTitle>
            <CardDescription>
              {isLoading
                ? 'Chargement…'
                : `${dossiers.length} dossier${dossiers.length > 1 ? 's' : ''}${
                    aDesFiltres ? ' correspondant aux filtres' : ''
                  }`}
            </CardDescription>
            <p className="mt-2 text-xs text-muted-foreground">
              Le <span className="font-medium">CONT</span> est le conteneur
              d&apos;archivage propre à chaque client : c&apos;est la partition
              du coffre-fort qui regroupe tous ses dossiers. Son identifiant est
              rappelé sous le nom du client.
            </p>
          </div>

          <form
            className="grid gap-3 md:grid-cols-2 xl:grid-cols-5"
            onSubmit={onSubmitFiltres}
          >
            <div className="space-y-1.5">
              <Label htmlFor="filtre-client">Client (CONT)</Label>
              <select
                id="filtre-client"
                value={saisie.id_cont ?? ''}
                onChange={(event) =>
                  setSaisie((current) => ({
                    ...current,
                    id_cont: event.target.value,
                  }))
                }
                className={cn(selectClassName, 'w-full')}
              >
                <option value="">Tous les clients</option>
                {optionsFiltres.clients.map((client) => (
                  <option key={client.id_cont} value={client.id_cont}>
                    {client.libelle === client.id_cont
                      ? client.id_cont
                      : `${client.libelle} — ${client.id_cont}`}
                  </option>
                ))}
              </select>
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="filtre-immatriculation">Immatriculation</Label>
              <Input
                id="filtre-immatriculation"
                placeholder="AA-123-BB"
                value={saisie.immatriculation ?? ''}
                onChange={(event) =>
                  setSaisie((current) => ({
                    ...current,
                    immatriculation: event.target.value,
                  }))
                }
              />
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="filtre-demarche">Démarche</Label>
              <select
                id="filtre-demarche"
                value={saisie.type_demarche ?? ''}
                onChange={(event) =>
                  setSaisie((current) => ({
                    ...current,
                    type_demarche: event.target.value,
                  }))
                }
                className={cn(selectClassName, 'w-full')}
              >
                <option value="">Toutes les démarches</option>
                {optionsFiltres.demarches.map((demarche) => (
                  <option key={demarche} value={demarche}>
                    {demarche}
                  </option>
                ))}
              </select>
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="filtre-date-debut">Date de début</Label>
              <Input
                id="filtre-date-debut"
                type="date"
                value={saisie.date_debut ?? ''}
                max={saisie.date_fin || undefined}
                onChange={(event) =>
                  setSaisie((current) => ({
                    ...current,
                    date_debut: event.target.value,
                  }))
                }
              />
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="filtre-date-fin">Date de fin</Label>
              <Input
                id="filtre-date-fin"
                type="date"
                value={saisie.date_fin ?? ''}
                min={saisie.date_debut || undefined}
                onChange={(event) =>
                  setSaisie((current) => ({
                    ...current,
                    date_fin: event.target.value,
                  }))
                }
              />
            </div>

            <div className="flex items-end gap-2 md:col-span-2 xl:col-span-5">
              <Button type="submit" disabled={isLoading}>
                {isLoading ? (
                  <Loader2 className="h-4 w-4 animate-spin" />
                ) : (
                  <Search className="h-4 w-4" />
                )}
                Filtrer
              </Button>
              <Button
                type="button"
                variant="outline"
                onClick={onReinitialiser}
                disabled={isLoading}
              >
                <RotateCcw className="h-4 w-4" />
                Réinitialiser
              </Button>

              <div className="ml-auto flex items-center gap-2">
                <Label htmlFor="taille-page" className="sr-only">
                  Lignes par page
                </Label>
                <select
                  id="taille-page"
                  value={pageSize}
                  onChange={(event) =>
                    setPageSize(
                      Number(
                        event.target.value,
                      ) as (typeof PAGE_SIZE_OPTIONS)[number],
                    )
                  }
                  className={cn(selectClassName, 'min-w-[140px]')}
                >
                  {PAGE_SIZE_OPTIONS.map((taille) => (
                    <option key={taille} value={taille}>
                      {taille} par page
                    </option>
                  ))}
                </select>
              </div>
            </div>
          </form>
        </CardHeader>

        <CardContent className="p-0">
          {isLoading ? (
            <div className="flex items-center justify-center gap-2 py-16 text-sm text-muted-foreground">
              <Loader2 className="h-5 w-5 animate-spin" />
              Chargement des dossiers…
            </div>
          ) : loadError ? (
            <div className="py-12 text-center text-sm text-destructive">
              {loadError}
            </div>
          ) : dossiers.length === 0 ? (
            <div className="flex flex-col items-center gap-2 px-6 py-12 text-center">
              <FolderOpen className="h-8 w-8 text-muted-foreground/60" />
              <p className="font-medium">Aucun dossier</p>
              <p className="text-sm text-muted-foreground">
                {filtresAppliques.id_cont
                  ? 'Créez le premier dossier de ce client.'
                  : aDesFiltres
                    ? 'Ajustez vos filtres pour afficher des dossiers.'
                    : 'Sélectionnez un client pour créer un dossier.'}
              </p>
            </div>
          ) : (
            <>
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>Client (CONT)</TableHead>
                    <TableHead>Dossier</TableHead>
                    <TableHead>Immatriculation</TableHead>
                    <TableHead>Démarche</TableHead>
                    <TableHead>Statut</TableHead>
                    <TableHead className="text-right">Documents</TableHead>
                    <TableHead>Créé par / créé le</TableHead>
                    <TableHead className="text-right">Action</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {dossiersPagines.map((dossier) => (
                    <TableRow key={dossier.id_dossier}>
                      <TableCell>
                        <div className="font-medium">
                          {nomClient(dossier) ?? (
                            <span className="text-muted-foreground">—</span>
                          )}
                        </div>
                        <div
                          className="font-mono text-xs text-muted-foreground"
                          title="Identifiant du conteneur (CONT) qui regroupe les dossiers de ce client"
                        >
                          CONT&nbsp;·&nbsp;
                          {dossier.conteneur?.id_cont ?? dossier.id_cont ?? '—'}
                        </div>
                      </TableCell>
                      <TableCell>{dossier.nom}</TableCell>
                      <TableCell className="font-mono uppercase">
                        {dossier.immatriculation ?? (
                          <span className="font-sans text-muted-foreground">
                            —
                          </span>
                        )}
                      </TableCell>
                      <TableCell>
                        {dossier.type_demarche ?? (
                          <span className="text-muted-foreground">—</span>
                        )}
                      </TableCell>
                      <TableCell>
                        <StatutDossierBadge dossier={dossier} />
                      </TableCell>
                      <TableCell className="text-right tabular-nums">
                        {dossier.objets_numeriques_count ?? 0}
                      </TableCell>
                      <TableCell className="whitespace-nowrap">
                        <div>
                          {dossier.cree_par?.nom ?? (
                            <span className="text-muted-foreground">—</span>
                          )}
                        </div>
                        <div className="text-xs text-muted-foreground">
                          {format(
                            new Date(dossier.created_at),
                            'dd MMM yyyy à HH:mm',
                            { locale: fr },
                          )}
                        </div>
                      </TableCell>
                      <TableCell className="text-right">
                        <Button
                          asChild
                          variant="ghost"
                          size="sm"
                          className="h-8 px-2"
                        >
                          <Link
                            href={`/coffre-fort/${dossier.conteneur?.id_cont ?? dossier.id_cont}/dossiers/${dossier.id_dossier}`}
                          >
                            Voir
                            <ExternalLink className="h-3.5 w-3.5" />
                          </Link>
                        </Button>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>

              <div className="flex flex-col gap-3 border-t px-4 py-4 sm:flex-row sm:items-center sm:justify-between">
                <p className="text-sm text-muted-foreground">
                  Affichage de {rangeStart} à {rangeEnd} sur {dossiers.length}{' '}
                  dossier{dossiers.length > 1 ? 's' : ''}
                </p>

                <div className="flex items-center gap-2">
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => setPage((current) => current - 1)}
                    disabled={currentPage <= 1}
                  >
                    <ChevronLeft className="h-4 w-4" />
                    Précédent
                  </Button>
                  <span className="min-w-[4.5rem] text-center text-sm tabular-nums text-muted-foreground">
                    {currentPage} / {totalPages}
                  </span>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => setPage((current) => current + 1)}
                    disabled={currentPage >= totalPages}
                  >
                    Suivant
                    <ChevronRight className="h-4 w-4" />
                  </Button>
                </div>
              </div>
            </>
          )}
        </CardContent>
      </Card>

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Créer un nouveau dossier</DialogTitle>
            <DialogDescription>
              Dans le conteneur{' '}
              {clientSelectionne?.libelle ?? filtresAppliques.id_cont}.
            </DialogDescription>
          </DialogHeader>

          <form onSubmit={handleSubmit(onCreateDossier)} className="space-y-4">
            <div className="space-y-2">
              <Label htmlFor="nom">
                Nom du dossier <span className="text-destructive">*</span>
              </Label>
              <Input
                id="nom"
                placeholder="Ex: Dossier carte grise"
                {...register('nom')}
              />
              {errors.nom ? (
                <p className="text-xs text-destructive">{errors.nom.message}</p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="description">Description</Label>
              <Textarea
                id="description"
                placeholder="Description optionnelle..."
                rows={3}
                {...register('description')}
              />
            </div>

            <div className="space-y-2">
              <Label htmlFor="immatriculation">Immatriculation</Label>
              <Input
                id="immatriculation"
                placeholder="AA-123-BB"
                maxLength={12}
                {...register('immatriculation')}
              />
              {errors.immatriculation ? (
                <p className="text-xs text-destructive">
                  {errors.immatriculation.message}
                </p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="type_demarche">Type de démarche</Label>
              <Input
                id="type_demarche"
                placeholder="Changement de titulaire, etc."
                {...register('type_demarche')}
              />
            </div>

            {submitError ? (
              <p className="text-sm text-destructive">{submitError}</p>
            ) : null}

            <DialogFooter>
              <Button
                type="button"
                variant="outline"
                onClick={() => setDialogOpen(false)}
                disabled={isSubmitting}
              >
                Annuler
              </Button>
              <Button type="submit" disabled={isSubmitting}>
                {isSubmitting ? (
                  <>
                    <Loader2 className="h-4 w-4 animate-spin" />
                    Création...
                  </>
                ) : (
                  'Créer'
                )}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </>
  );
}
