"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import Link from "next/link";
import { FileSpreadsheet, FileUp, RefreshCw, TriangleAlert, Upload, X } from "lucide-react";
import * as XLSX from "xlsx";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } 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 { nativeSelectClassName } from "@/components/fichas/form-fields";
import type { ImportExecutionResult, ImportMode, ImportPreviewResult, ImportRawRow } from "@/lib/importar";
import { semanticBadgeClass, semanticSurfaceClass } from "@/lib/badge-variants";
import type { SemanticTone } from "@/lib/semantic-tokens";
import { importRowStatusTone, surfaceClassForAlertTone } from "@/lib/state-variants";
import { cn } from "@/lib/utils";

type MetricTone = Exclude<SemanticTone, "primary" | "destructive">;

const statusLabels: Record<string, string> = {
  VALIDO: "Válido",
  EXISTENTE: "Existente",
  DUPLICADO: "Duplicado",
  ERROR: "Error",
};

export function ImportarDashboard() {
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const [mode, setMode] = useState<ImportMode>("CREATE_ONLY");
  const [fileName, setFileName] = useState("");
  const [rawRows, setRawRows] = useState<ImportRawRow[]>([]);
  const [preview, setPreview] = useState<ImportPreviewResult | null>(null);
  const [result, setResult] = useState<ImportExecutionResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [importing, setImporting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [confirmOpen, setConfirmOpen] = useState(false);

  useEffect(() => {
    if (!rawRows.length) return;
    void refreshPreview(rawRows, mode);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [mode]);

  const importablesCount = preview?.summary.listasParaImportar ?? 0;
  const disabledImport = loading || importing || !preview || importablesCount === 0;

  async function refreshPreview(rows: ImportRawRow[], nextMode: ImportMode) {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch("/api/importar/preview", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ rows, mode: nextMode }),
      });
      const data = (await response.json()) as ImportPreviewResult & { error?: string };
      if (!response.ok) {
        throw new Error(data.error ?? "No se pudo previsualizar el archivo.");
      }
      setPreview(data);
      setResult(null);
    } catch (err) {
      const message = err instanceof Error ? err.message : "No se pudo previsualizar el archivo.";
      setError(message);
      setPreview(null);
      toast.error(message);
    } finally {
      setLoading(false);
    }
  }

  async function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;

    if (!/\.xls(x)?$/i.test(file.name)) {
      setError("Selecciona un archivo .xls o .xlsx válido.");
      setPreview(null);
      setRawRows([]);
      setFileName("");
      toast.error("Selecciona un archivo .xls o .xlsx válido.");
      return;
    }

    setFileName(file.name);
    setResult(null);

    try {
      setLoading(true);
      const buffer = await file.arrayBuffer();
      const workbook = XLSX.read(buffer, { type: "array", cellDates: true });
      const sheetName = workbook.SheetNames[0];
      if (!sheetName) throw new Error("El archivo no contiene hojas visibles.");
      const sheet = workbook.Sheets[sheetName];
      const rows = XLSX.utils.sheet_to_json<Record<string, unknown>>(sheet, { defval: "", raw: true });
      setRawRows(rows);
      await refreshPreview(rows, mode);
    } catch (err) {
      const message = err instanceof Error ? err.message : "No se pudo leer el archivo Excel.";
      setError(message);
      setPreview(null);
      setRawRows([]);
      toast.error(message);
    } finally {
      setLoading(false);
      if (fileInputRef.current) fileInputRef.current.value = "";
    }
  }

  function handleReset() {
    setMode("CREATE_ONLY");
    setFileName("");
    setRawRows([]);
    setPreview(null);
    setResult(null);
    setError(null);
    if (fileInputRef.current) fileInputRef.current.value = "";
  }

  async function handleImport() {
    if (!rawRows.length) return;
    setImporting(true);
    setError(null);
    try {
      const response = await fetch("/api/importar/run", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ rows: rawRows, mode }),
      });
      const data = (await response.json()) as ImportExecutionResult & { error?: string };
      if (!response.ok) {
        throw new Error(data.error ?? "No se pudo ejecutar la importación.");
      }
      setResult(data);
      toast.success("Importación completada.");
      setConfirmOpen(false);
    } catch (err) {
      const message = err instanceof Error ? err.message : "No se pudo ejecutar la importación.";
      setError(message);
      toast.error(message);
    } finally {
      setImporting(false);
    }
  }

  const summaryCards = useMemo(
    () => [
      { label: "Total filas", value: preview?.summary.total ?? 0, tone: "neutral" as const },
      { label: "Listas para importar", value: preview?.summary.listasParaImportar ?? 0, tone: "success" as const },
      { label: "Con errores", value: preview?.summary.errores ?? 0, tone: "danger" as const },
      { label: "Duplicadas", value: preview?.summary.duplicadas ?? 0, tone: "warning" as const },
      { label: "Existentes", value: preview?.summary.existentes ?? 0, tone: "info" as const },
    ],
    [preview],
  );

  return (
    <div className="space-y-6">
      <section className="grid gap-4 xl:grid-cols-3">
        <Card className="border-border shadow-sm xl:col-span-2">
          <CardHeader>
            <CardTitle>Descargar plantilla</CardTitle>
            <CardDescription>
              Usa este formato para cargar fichas territoriales de manera masiva. La plantilla contiene los encabezados
              esperados por el importador.
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="grid gap-3 md:grid-cols-2">
              <InfoBox
                title="Validación previa"
                description="No se importa nada al subir el archivo. El sistema siempre genera una vista previa antes de confirmar."
              />
              <InfoBox
                title="Modo de importación"
                description="Puedes crear solo fichas nuevas o crear nuevas y actualizar las existentes con manzana + lote."
              />
            </div>
            <div className="flex flex-wrap gap-2">
              <Button asChild className="gap-2">
                <Link href="/api/importar/plantilla">
                  <FileSpreadsheet className="h-4 w-4" />
                  Descargar plantilla Excel
                </Link>
              </Button>
              <Button variant="outline" className="gap-2" type="button" onClick={handleReset} disabled={!preview && !fileName}>
                <X className="h-4 w-4" />
                Cancelar
              </Button>
            </div>
          </CardContent>
        </Card>

        <Card className="border-border shadow-sm">
          <CardHeader>
            <CardTitle>Subir Excel</CardTitle>
            <CardDescription>Selecciona un archivo .xlsx o .xls para generar la vista previa.</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="space-y-2">
              <Label htmlFor="mode">Modo de importación</Label>
              <select
                id="mode"
                value={mode}
                onChange={(event) => setMode(event.target.value as ImportMode)}
                className={nativeSelectClassName}
              >
                <option value="CREATE_ONLY">Crear solo nuevas fichas</option>
                <option value="UPSERT">Crear nuevas y actualizar existentes</option>
              </select>
            </div>
            <div className="space-y-2">
              <Label htmlFor="archivo">Archivo Excel</Label>
              <Input
                ref={fileInputRef}
                id="archivo"
                name="archivo"
                type="file"
                accept=".xlsx,.xls"
                onChange={handleFileChange}
              />
              {fileName ? <p className="text-xs text-muted-foreground">Archivo cargado: {fileName}</p> : null}
            </div>
            <div className="flex items-center gap-2 text-xs text-muted-foreground">
              <Upload className="h-3.5 w-3.5" />
              La lectura se hace al seleccionar el archivo. Luego confirmas la importación.
            </div>
          </CardContent>
        </Card>
      </section>

      {error ? (
        <Card className={cn(surfaceClassForAlertTone("danger"), "shadow-sm")}>
          <CardContent className="flex items-center gap-2 p-4 text-sm">
            <TriangleAlert className="h-4 w-4" />
            {error}
          </CardContent>
        </Card>
      ) : null}

      {preview ? (
        <>
          <section className="grid gap-4 md:grid-cols-2 xl:grid-cols-5">
            {summaryCards.map((item) => (
              <MetricCard key={item.label} label={item.label} value={item.value} tone={item.tone} />
            ))}
          </section>

          {result ? (
            <Card className="border-border shadow-sm">
              <CardHeader>
                <CardTitle>Resultado de importación</CardTitle>
                <CardDescription>Resumen final luego de ejecutar el proceso.</CardDescription>
              </CardHeader>
              <CardContent className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
                <MetricCard label="Importadas" value={result.summary.importadas} tone="success" />
                <MetricCard label="Actualizadas" value={result.summary.actualizadas} tone="info" />
                <MetricCard label="Omitidas" value={result.summary.omitidas} tone="warning" />
                <MetricCard label="Errores" value={result.summary.errores} tone="danger" />
              </CardContent>
            </Card>
          ) : null}

          <Card className="border-border shadow-sm">
            <CardHeader className="flex flex-row items-center justify-between gap-3">
              <div>
                <CardTitle>Vista previa</CardTitle>
                <CardDescription>Revisa los errores antes de confirmar la importación.</CardDescription>
              </div>
              <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>
                <DialogTrigger asChild>
                  <Button disabled={disabledImport} className="gap-2">
          <FileUp className="h-4 w-4" />
                    Importar datos válidos
                  </Button>
                </DialogTrigger>
                <DialogContent className="sm:max-w-xl">
                  <DialogHeader>
                    <DialogTitle>Confirmar importación</DialogTitle>
                    <DialogDescription>
                      Se importarán solo las filas válidas. Las filas con error o duplicadas quedarán fuera del proceso.
                    </DialogDescription>
                  </DialogHeader>
                  <div className="grid gap-3 md:grid-cols-2">
                    <MetricCard label="Listas para importar" value={preview.summary.listasParaImportar} tone="success" />
                    <MetricCard label="Con errores" value={preview.summary.errores} tone="danger" />
                  </div>
                  <DialogFooter>
                    <Button type="button" variant="outline" onClick={() => setConfirmOpen(false)}>
                      Cancelar
                    </Button>
                    <Button type="button" onClick={handleImport} disabled={importing}>
                      {importing ? <RefreshCw className="mr-2 h-4 w-4 animate-spin" /> : null}
                      Confirmar importación
                    </Button>
                  </DialogFooter>
                </DialogContent>
              </Dialog>
            </CardHeader>
            <CardContent className="overflow-x-auto p-0">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>Fila Excel</TableHead>
                    <TableHead>Manzana</TableHead>
                    <TableHead>Lote</TableHead>
                    <TableHead>Dirección</TableHead>
                    <TableHead>Ocupante</TableHead>
                    <TableHead>RUT</TableHead>
                    <TableHead>Estado validación</TableHead>
                    <TableHead>Errores detectados</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {preview.rows.map((row) => (
                    <TableRow key={`${row.rowNumber}-${row.lote}`}>
                      <TableCell className="whitespace-nowrap font-medium">{row.rowNumber}</TableCell>
                      <TableCell className="whitespace-nowrap">{row.manzana}</TableCell>
                      <TableCell className="whitespace-nowrap">{row.lote}</TableCell>
                      <TableCell className="max-w-64 truncate" title={row.direccion}>
                        {row.direccion}
                      </TableCell>
                      <TableCell className="max-w-52 truncate" title={row.ocupante}>
                        {row.ocupante}
                      </TableCell>
                      <TableCell className="whitespace-nowrap">{row.rut}</TableCell>
                      <TableCell>
                        <Badge className={semanticBadgeClass(importRowStatusTone(row.estado), { shape: "pill" })}>
                          {statusLabels[row.estado]}
                        </Badge>
                      </TableCell>
                      <TableCell>
                        {row.errores.length === 0 ? (
                          <span className="text-sm text-muted-foreground">-</span>
                        ) : (
                          <ul className="list-disc space-y-1 pl-4 text-sm text-foreground">
                            {row.errores.map((errorItem, index) => (
                              <li key={`${row.rowNumber}-${index}`}>{errorItem}</li>
                            ))}
                          </ul>
                        )}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </CardContent>
          </Card>
        </>
      ) : (
        <Card className="border-dashed border-border bg-muted shadow-sm">
          <CardContent className="flex flex-col items-center justify-center gap-3 py-12 text-center">
            <FileSpreadsheet className="h-10 w-10 text-muted-foreground" />
            <div className="space-y-1">
              <p className="text-sm font-medium text-foreground">Carga una plantilla para ver la vista previa</p>
              <p className="text-sm text-muted-foreground">
                El sistema validará cada fila antes de permitir la importación masiva.
              </p>
            </div>
          </CardContent>
        </Card>
      )}
    </div>
  );
}

function MetricCard({ label, value, tone }: { label: string; value: number | string; tone: MetricTone }) {
  return (
    <Card className={cn("shadow-sm", semanticSurfaceClass(tone, { padding: "none" }))}>
      <CardContent className="p-4">
        <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">{label}</p>
        <p className="mt-2 text-2xl font-semibold text-foreground">{value}</p>
      </CardContent>
    </Card>
  );
}

function InfoBox({ title, description }: { title: string; description: string }) {
  return (
    <div className={semanticSurfaceClass("neutral", { padding: "md" })}>
      <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">{title}</p>
      <p className="mt-1 text-sm text-foreground">{description}</p>
    </div>
  );
}
