'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,
  Plus,
  Power,
  PowerOff,
  Search,
  Shield,
} from 'lucide-react';
import Link from 'next/link';
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 { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import {
  createConteneur,
  extractApiErrorMessage,
  fetchConteneurs,
  fetchMe,
  updateConteneur,
  type AuthUser,
  type Conteneur,
} from '@/lib/api';
import { cn } from '@/lib/utils';

const createConteneurSchema = z.object({
  libelle: z.string().max(255).optional(),
  reference_externe: z.string().max(255).optional(),
});

type CreateConteneurFormValues = z.infer<typeof createConteneurSchema>;
type StatutFilter = 'all' | 'actif' | 'inactif';

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';

function matchesSearch(conteneur: Conteneur, query: string): boolean {
  const normalizedQuery = query.trim().toLowerCase();

  if (!normalizedQuery) {
    return true;
  }

  const fields = [
    conteneur.id_cont,
    conteneur.libelle,
    conteneur.reference_externe,
  ];

  return fields.some((field) =>
    field?.toLowerCase().includes(normalizedQuery),
  );
}

function formatBytes(bytes: number | null | undefined): string {
  if (bytes == null) {
    return '—';
  }

  if (bytes < 1024) {
    return `${bytes} o`;
  }

  if (bytes < 1024 * 1024) {
    return `${Math.round(bytes / 1024)} Ko`;
  }

  return `${(bytes / (1024 * 1024)).toFixed(1)} Mo`;
}

function matchesStatut(conteneur: Conteneur, statut: StatutFilter): boolean {
  if (statut === 'all') {
    return true;
  }

  return statut === 'actif' ? conteneur.actif : !conteneur.actif;
}

export function DossiersPanel() {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [conteneurs, setConteneurs] = useState<Conteneur[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [dialogOpen, setDialogOpen] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const [togglingId, setTogglingId] = useState<string | null>(null);
  const [toggleError, setToggleError] = useState<string | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const [statutFilter, setStatutFilter] = useState<StatutFilter>('all');
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState<(typeof PAGE_SIZE_OPTIONS)[number]>(
    PAGE_SIZE_OPTIONS[0],
  );

  // §5.7.4 : seul l'Administrateur Fonctionnel gère les conteneurs.
  const canManageConteneur = user?.role_ccfn === 'UTI-F';
  // §5.6.1 et §5.6.2 : les administrateurs n'accèdent pas au contenu des
  // conteneurs ; le lien vers la liste des dossiers leur est donc fermé.
  const canVoirDossiers = user?.role_ccfn === 'UTI-S';
  const showCreateButton = !isLoading && !loadError && canManageConteneur;

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<CreateConteneurFormValues>({
    resolver: zodResolver(createConteneurSchema),
    defaultValues: {
      libelle: '',
      reference_externe: '',
    },
  });

  const filteredConteneurs = useMemo(
    () =>
      conteneurs.filter(
        (conteneur) =>
          matchesSearch(conteneur, searchQuery) &&
          matchesStatut(conteneur, statutFilter),
      ),
    [conteneurs, searchQuery, statutFilter],
  );

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

  const paginatedConteneurs = useMemo(() => {
    const start = (currentPage - 1) * pageSize;
    return filteredConteneurs.slice(start, start + pageSize);
  }, [filteredConteneurs, currentPage, pageSize]);

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

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

  useEffect(() => {
    if (page > totalPages) {
      setPage(totalPages);
    }
  }, [page, totalPages]);

  const loadConteneurs = useCallback(async () => {
    setIsLoading(true);
    setLoadError(null);

    try {
      const [currentUser, conteneurList] = await Promise.all([
        fetchMe(),
        fetchConteneurs(),
      ]);

      setUser(currentUser);
      setConteneurs(conteneurList);
    } catch (error) {
      if (isAxiosError(error) && error.response?.status === 401) {
        setLoadError('Session expirée. Veuillez vous reconnecter.');
      } else {
        setLoadError('Impossible de charger les conteneurs.');
      }
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    void loadConteneurs();
  }, [loadConteneurs]);

  async function onCreateConteneur(values: CreateConteneurFormValues) {
    setSubmitError(null);

    try {
      const payload = {
        libelle: values.libelle?.trim() || undefined,
        reference_externe: values.reference_externe?.trim() || undefined,
      };

      const conteneur = await createConteneur(payload);
      setConteneurs((current) => [conteneur, ...current]);
      reset();
      setDialogOpen(false);
    } catch (error) {
      if (isAxiosError(error)) {
        if (error.response?.status === 403) {
          setSubmitError(
            'Votre profil ne permet pas de créer un conteneur (UTI-F requis).',
          );
        } else if (error.response?.status === 422) {
          setSubmitError('Vérifiez les informations saisies.');
        } else {
          setSubmitError('Impossible de créer le conteneur.');
        }
      } else {
        setSubmitError('Impossible de créer le conteneur.');
      }
    }
  }

  async function onToggleActif(conteneur: Conteneur) {
    setToggleError(null);
    setTogglingId(conteneur.id_cont);

    try {
      const updated = await updateConteneur(conteneur.id_cont, {
        actif: !conteneur.actif,
      });

      setConteneurs((current) =>
        current.map((item) =>
          item.id_cont === updated.id_cont ? { ...item, ...updated } : item,
        ),
      );
    } catch (error) {
      setToggleError(
        extractApiErrorMessage(
          error,
          'Impossible de modifier le statut du conteneur.',
        ),
      );
    } finally {
      setTogglingId(null);
    }
  }

  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">
            <Shield className="h-6 w-6 text-primary" />
          </div>
          <div>
            <h1 className="text-2xl font-bold tracking-tight">Coffre-fort</h1>
            <p className="text-sm text-muted-foreground">
              Gérez vos dossiers d&apos;archivage et pièces justificatives
            </p>
          </div>
        </div>

        {showCreateButton ? (
          <Button type="button" onClick={() => setDialogOpen(true)}>
            <Plus className="h-4 w-4" />
            Créer un conteneur
          </Button>
        ) : null}
      </div>

      {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 conteneurs…
        </div>
      ) : loadError ? (
        <Card>
          <CardContent className="py-10 text-center text-sm text-destructive">
            {loadError}
          </CardContent>
        </Card>
      ) : conteneurs.length === 0 ? (
        <Card>
          <CardContent className="flex flex-col items-center gap-3 py-12 text-center">
            <FolderOpen className="h-10 w-10 text-muted-foreground/60" />
            <div>
              <p className="font-medium">Aucun conteneur pour le moment</p>
              <p className="mt-1 text-sm text-muted-foreground">
                Créez votre premier conteneur (CONT) pour organiser vos dossiers.
              </p>
            </div>
            {showCreateButton ? (
              <Button type="button" onClick={() => setDialogOpen(true)}>
                <Plus className="h-4 w-4" />
                Créer un conteneur
              </Button>
            ) : null}
          </CardContent>
        </Card>
      ) : (
        <Card>
          <CardHeader className="gap-4 border-b pb-6">
            <div className="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
              <div>
                <CardTitle className="text-base">Dossiers d&apos;archivage</CardTitle>
                <CardDescription>
                  {filteredConteneurs.length} conteneur
                  {filteredConteneurs.length > 1 ? 's' : ''}
                  {filteredConteneurs.length !== conteneurs.length
                    ? ` sur ${conteneurs.length}`
                    : ''}
                </CardDescription>
              </div>
            </div>

            <div className="flex flex-col gap-3 lg:flex-row lg:items-center">
              <div className="relative flex-1">
                <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
                <Input
                  type="search"
                  placeholder="Rechercher par référence, libellé…"
                  value={searchQuery}
                  onChange={(event) => setSearchQuery(event.target.value)}
                  className="pl-9"
                />
              </div>

              <div className="flex flex-col gap-2 sm:flex-row sm:items-center">
                <Label htmlFor="statut-filter" className="sr-only">
                  Statut
                </Label>
                <select
                  id="statut-filter"
                  value={statutFilter}
                  onChange={(event) =>
                    setStatutFilter(event.target.value as StatutFilter)
                  }
                  className={cn(selectClassName, 'min-w-[140px]')}
                >
                  <option value="all">Tous les statuts</option>
                  <option value="actif">Actifs</option>
                  <option value="inactif">Inactifs</option>
                </select>

                <Label htmlFor="page-size" className="sr-only">
                  Lignes par page
                </Label>
                <select
                  id="page-size"
                  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((size) => (
                    <option key={size} value={size}>
                      {size} par page
                    </option>
                  ))}
                </select>
              </div>
            </div>

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

          <CardContent className="p-0">
            {filteredConteneurs.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 résultat</p>
                <p className="text-sm text-muted-foreground">
                  Ajustez vos filtres pour afficher des conteneurs.
                </p>
              </div>
            ) : (
              <>
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead>Référence</TableHead>
                      <TableHead>Libellé</TableHead>
                      <TableHead>Référence externe</TableHead>
                      <TableHead>Statut</TableHead>
                      <TableHead className="text-right">Dossiers</TableHead>
                      <TableHead>Créé par</TableHead>
                      <TableHead>Créé le</TableHead>
                      <TableHead className="text-right">Action</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {paginatedConteneurs.map((conteneur) => (
                      <TableRow key={conteneur.id_cont}>
                        <TableCell className="font-mono text-xs">
                          {conteneur.id_cont}
                        </TableCell>
                        <TableCell>
                          {conteneur.libelle ?? (
                            <span className="text-muted-foreground">—</span>
                          )}
                        </TableCell>
                        <TableCell>
                          {conteneur.reference_externe ?? (
                            <span className="text-muted-foreground">—</span>
                          )}
                        </TableCell>
                        <TableCell>
                          <span
                            className={cn(
                              'inline-flex rounded-full px-2 py-0.5 text-xs font-medium',
                              conteneur.actif
                                ? 'bg-emerald-100 text-emerald-700'
                                : 'bg-muted text-muted-foreground',
                            )}
                          >
                            {conteneur.actif ? 'Actif' : 'Inactif'}
                          </span>
                        </TableCell>
                        <TableCell className="text-right tabular-nums">
                          {conteneur.dossiers_count ?? 0}
                        </TableCell>
                        <TableCell>
                          {conteneur.cree_par?.nom ?? (
                            <span className="text-muted-foreground">—</span>
                          )}
                        </TableCell>
                        <TableCell className="whitespace-nowrap text-muted-foreground">
                          {format(
                            new Date(conteneur.created_at),
                            'dd MMM yyyy à HH:mm',
                            { locale: fr },
                          )}
                        </TableCell>
                        <TableCell className="text-right">
                          <div className="flex items-center justify-end gap-1">
                            {canManageConteneur ? (
                              <Button
                                type="button"
                                variant="ghost"
                                size="sm"
                                className="h-8 px-2"
                                onClick={() => void onToggleActif(conteneur)}
                                disabled={togglingId === conteneur.id_cont}
                              >
                                {togglingId === conteneur.id_cont ? (
                                  <Loader2 className="h-3.5 w-3.5 animate-spin" />
                                ) : conteneur.actif ? (
                                  <PowerOff className="h-3.5 w-3.5" />
                                ) : (
                                  <Power className="h-3.5 w-3.5" />
                                )}
                                {conteneur.actif ? 'Désactiver' : 'Réactiver'}
                              </Button>
                            ) : null}

                            {canVoirDossiers ? (
                              <Button
                                asChild
                                variant="ghost"
                                size="sm"
                                className="h-8 px-2"
                              >
                                <Link
                                  href={`/liste-dossiers?id_cont=${conteneur.id_cont}`}
                                >
                                  Voir
                                  <ExternalLink className="h-3.5 w-3.5" />
                                </Link>
                              </Button>
                            ) : null}
                          </div>
                        </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{' '}
                    {filteredConteneurs.length} conteneur
                    {filteredConteneurs.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>Nouveau conteneur</DialogTitle>
            <DialogDescription>
              Créez un conteneur (CONT) pour organiser vos dossiers et pièces justificatives.
            </DialogDescription>
          </DialogHeader>

          <form
            className="space-y-4"
            onSubmit={handleSubmit(onCreateConteneur)}
          >
            <div className="space-y-2">
              <Label htmlFor="libelle">Libellé</Label>
              <Input
                id="libelle"
                placeholder="Description du conteneur"
                {...register('libelle')}
              />
              {errors.libelle ? (
                <p className="text-xs text-destructive">{errors.libelle.message}</p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="reference_externe">Référence externe</Label>
              <Input
                id="reference_externe"
                placeholder="Référence externe (ex: numéro partenaire)"
                {...register('reference_externe')}
              />
              {errors.reference_externe ? (
                <p className="text-xs text-destructive">{errors.reference_externe.message}</p>
              ) : null}
            </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 le conteneur'
                )}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </>
  );
}
