"use client";

import { useEffect, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { DashboardEmptyState, DashboardPageIntro, DashboardSection } from "@/components/dashboard-page";
import { FacturacionPosConfigForm } from "@/components/facturacion-pos-config-form";
import { useAuth } from "@/components/providers";
import { Button } from "@/components/ui/button";
import { ErrorState } from "@/components/ui/error-state";
import { Input } from "@/components/ui/input";
import { useToast } from "@/hooks/use-toast";
import { configuracionApi, type CatalogoParametroEntrada, type ValorParaUI } from "@/lib/api";
import { AlertTriangle, Loader2, Save, Settings } from "lucide-react";

type FormularioTenant = Record<string, string | boolean>;

const ORDEN_GRUPOS = ["facturacion", "inventario", "productos", "tiendas", "notificaciones"] as const;

const ETIQUETAS_GRUPO: Record<string, string> = {
  facturacion: "Facturación",
  inventario: "Inventario",
  productos: "Productos",
  tiendas: "Tiendas",
  notificaciones: "Notificaciones (WhatsApp)",
};

// Espejo del MAPEO_TENANT del backend (taller-parametros.mapeo.ts) -- clave
// del catálogo -> campo camelCase que espera ActualizarParametrosTenantDto.
// Se duplica a propósito (frontend y backend no comparten paquete de tipos
// hoy): mismo criterio que ya usan authApi/UpdateTiendaFacturacionPosDto.
const CLAVE_A_CAMPO_API: Record<string, string> = {
  "facturacion.usa_facturacion": "usaFacturacion",
  "inventario.usa_validacion": "usaValidacionInventario",
  "productos.permite_crear": "permiteCrearProductos",
  "tiendas.permite_crear": "permiteCrearTiendas",
  "notificaciones.usa_whatsapp": "usaWhatsapp",
  "notificaciones.whatsapp_phone_number_id": "whatsappPhoneNumberId",
  "notificaciones.whatsapp_access_token": "whatsappAccessToken",
  "notificaciones.whatsapp_api_version": "whatsappApiVersion",
  "notificaciones.whatsapp_template_cotizacion": "whatsappTemplateCotizacion",
  "notificaciones.whatsapp_template_estado": "whatsappTemplateEstado",
  "notificaciones.whatsapp_template_language": "whatsappTemplateLanguage",
  "notificaciones.whatsapp_default_country_code": "whatsappDefaultCountryCode",
};

function valorInicial(entrada: CatalogoParametroEntrada, valorActual: ValorParaUI | undefined): string | boolean {
  if (entrada.sensible) return "";
  if (entrada.tipo === "boolean") return Boolean(valorActual ?? entrada.default ?? false);
  if (valorActual === undefined || valorActual === null) {
    return entrada.default !== undefined ? String(entrada.default) : "";
  }
  return String(valorActual);
}

// Estado ausente ("falta esto") calculado con el mismo criterio que el
// backend usa para requeridoSi -- valor efectivo (form actual) vacío
// mientras su gate está en true. Sin llamar al backend: el catálogo y el
// resumen ya están en memoria.
// Mismo criterio que el backend usa para envolver un valor sensible en el
// resumen ({configurado: boolean} en vez del secreto real) -- ver
// taller-parametros.service.ts#valorParaUI.
function estaConfigurado(valor: ValorParaUI | undefined): boolean {
  return typeof valor === "object" && valor !== null && Boolean((valor as { configurado?: boolean }).configurado);
}

function calcularFaltantes(
  catalogo: Record<string, CatalogoParametroEntrada>,
  form: FormularioTenant,
  resumenTenant: Record<string, ValorParaUI>,
  resumenTiendas: Array<{ tiendaId: number; nombre: string; parametros: Record<string, ValorParaUI> }>,
): string[] {
  const faltantes: string[] = [];

  for (const [clave, entrada] of Object.entries(catalogo)) {
    if (entrada.ambito !== "tenant" || !entrada.requeridoSi) continue;
    const gateEncendido = Boolean(form[entrada.requeridoSi]);
    if (!gateEncendido) continue;

    if (entrada.sensible) {
      // Los campos sensibles siempre se resetean a "" en el form (nunca se
      // precargan, ver valorInicial) -- comparar contra el form marcaría un
      // secreto YA guardado como "falta" para siempre. Comparamos contra el
      // valor real del resumen, que para sensibles llega como {configurado}.
      if (!estaConfigurado(resumenTenant[clave])) {
        faltantes.push(`${entrada.etiqueta} (${catalogo[entrada.requeridoSi]?.etiqueta ?? entrada.requeridoSi})`);
      }
      continue;
    }

    const valor = form[clave];
    if (valor === "" || valor === undefined) {
      faltantes.push(`${entrada.etiqueta} (${catalogo[entrada.requeridoSi]?.etiqueta ?? entrada.requeridoSi})`);
    }
  }

  // Generalizado sobre TODO el catálogo de ámbito "tienda" con requeridoSi --
  // igual que el bucle de arriba, y que validarRequeridoSi() en el backend
  // (taller-parametros.service.ts): así cualquier clave nueva del catálogo
  // (ej. facturacion_pos.precio_decimales) queda cubierta sin tocar esta
  // función, en vez de una lista fija de 3 campos + password a mano.
  for (const [clave, entrada] of Object.entries(catalogo)) {
    if (entrada.ambito !== "tienda" || !entrada.requeridoSi) continue;

    for (const tienda of resumenTiendas) {
      const gateEncendido = Boolean(tienda.parametros[entrada.requeridoSi]);
      if (!gateEncendido) continue;

      if (entrada.sensible) {
        if (!estaConfigurado(tienda.parametros[clave])) {
          faltantes.push(`${entrada.etiqueta} — tienda ${tienda.nombre}`);
        }
        continue;
      }

      const valor = tienda.parametros[clave];
      if (valor === "" || valor === undefined) {
        faltantes.push(`${entrada.etiqueta} — tienda ${tienda.nombre}`);
      }
    }
  }

  return faltantes;
}

export default function ConfiguracionPage() {
  const router = useRouter();
  const { canRead, canWrite } = useAuth();
  const { toast } = useToast();
  const queryClient = useQueryClient();
  // "configuracion" dejó de ser un módulo plano: cada grupo real del
  // catálogo (facturación/inventario/productos/tiendas/notificaciones)
  // tiene su propio permiso -- ver auth/default-permissions.ts (backend) y
  // providers.tsx (frontend). puedeVer es true si el usuario puede leer AL
  // MENOS uno; cada sección de abajo se filtra por su propio grupo.
  const puedeVer = ORDEN_GRUPOS.some((grupo) => canRead(`configuracion.${grupo}`));
  const puedeEditarAlgunGrupo = ORDEN_GRUPOS.some((grupo) => canWrite(`configuracion.${grupo}`));

  const catalogoQuery = useQuery({
    queryKey: ["configuracion", "catalogo"],
    queryFn: configuracionApi.catalogo,
    enabled: puedeVer,
  });
  const resumenQuery = useQuery({
    queryKey: ["configuracion"],
    queryFn: configuracionApi.resumen,
    enabled: puedeVer,
  });

  // Solo los grupos que el usuario puede leer -- el catálogo (getCatalogo())
  // no tiene guard de permisos en el backend, así que sin este filtro el
  // form intentaría inicializar/mostrar "faltantes" de grupos que ni
  // siquiera aparecen en resumenQuery.data.tenant (excluidos ahí por el
  // filtro puedeLeerGrupo del controller).
  const clavesTenant = useMemo(
    () =>
      Object.entries(catalogoQuery.data ?? {}).filter(
        ([, entrada]) => entrada.ambito === "tenant" && canRead(`configuracion.${entrada.grupo}`),
      ),
    [catalogoQuery.data, canRead],
  );

  const [form, setForm] = useState<FormularioTenant>({});

  useEffect(() => {
    if (!catalogoQuery.data || !resumenQuery.data) return;
    const inicial: FormularioTenant = {};
    for (const [clave, entrada] of clavesTenant) {
      inicial[clave] = valorInicial(entrada, resumenQuery.data.tenant[clave]);
    }
    setForm(inicial);
  }, [catalogoQuery.data, resumenQuery.data, clavesTenant]);

  const guardarMutation = useMutation({
    mutationFn: async () => {
      const cuerpo: Record<string, boolean | string | undefined> = {};
      for (const [clave, entrada] of clavesTenant) {
        if (!canWrite(`configuracion.${entrada.grupo}`)) continue;
        const campoApi = CLAVE_A_CAMPO_API[clave];
        if (!campoApi) continue;
        const valor = form[clave];
        cuerpo[campoApi] = entrada.sensible && valor === "" ? undefined : valor;
      }
      return configuracionApi.actualizarTenant(cuerpo);
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["configuracion"] });
      setForm((current) => {
        const limpio = { ...current };
        for (const [clave, entrada] of clavesTenant) {
          if (entrada.sensible) limpio[clave] = "";
        }
        return limpio;
      });
      toast({ variant: "success", title: "Configuración guardada" });
    },
    onError: (error: any) =>
      toast({
        variant: "destructive",
        title: "No se pudo guardar",
        description: error.message || "Revisá los datos e intentá de nuevo.",
      }),
  });

  if (!puedeVer) {
    return (
      <main className="mx-auto max-w-4xl p-6">
        <DashboardEmptyState
          title="Sin acceso"
          description="Solo administrador o super admin pueden ver la configuración del taller."
          icon={Settings}
        />
      </main>
    );
  }

  if (catalogoQuery.isLoading || resumenQuery.isLoading) {
    return (
      <main className="mx-auto max-w-5xl p-6">
        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
      </main>
    );
  }

  if (catalogoQuery.isError || resumenQuery.isError || !catalogoQuery.data || !resumenQuery.data) {
    return (
      <main className="mx-auto max-w-5xl p-6">
        <ErrorState
          onRetry={() => {
            catalogoQuery.refetch();
            resumenQuery.refetch();
          }}
          description="No se pudo cargar la configuración del taller."
        />
      </main>
    );
  }

  const faltantes = calcularFaltantes(catalogoQuery.data, form, resumenQuery.data.tenant, resumenQuery.data.tiendas);
  const usaWhatsapp = Boolean(form["notificaciones.usa_whatsapp"]);

  return (
    <div className="min-h-full pb-16 md:pb-10">
      <main className="mx-auto flex max-w-5xl flex-col gap-6 p-4 md:p-6">
        <DashboardPageIntro
          title="Configuración"
          description="Toda la configuración del módulo de talleres: facturación, inventario, productos, tiendas y notificaciones."
          icon={Settings}
          tone="slate"
          onBack={() => router.push("/dashboard")}
        />

        {faltantes.length > 0 ? (
          <div className="flex items-start gap-3 rounded-xl border border-warning/40 bg-warning-soft p-4">
            <AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-warning" />
            <div>
              <p className="text-sm font-bold text-foreground">Falta completar {faltantes.length} campo(s)</p>
              <ul className="mt-1 list-inside list-disc text-sm text-muted-foreground">
                {faltantes.map((item) => (
                  <li key={item}>{item}</li>
                ))}
              </ul>
            </div>
          </div>
        ) : null}

        {/* Sin filtro a nivel de grupo: "notificaciones" siempre se renderiza
            (si tiene claves) para que su propio toggle de WhatsApp siempre
            se vea, sin importar canWrite ni el estado del toggle -- el
            ocultamiento del resto de sus campos pasa adentro, campo por
            campo, más abajo. */}
        {ORDEN_GRUPOS.map((grupo) => {
          if (!canRead(`configuracion.${grupo}`)) return null;
          const clavesDelGrupo = clavesTenant.filter(([, entrada]) => entrada.grupo === grupo);
          if (clavesDelGrupo.length === 0) return null;
          const puedeEditarGrupo = canWrite(`configuracion.${grupo}`);

          return (
            <DashboardSection key={grupo} title={ETIQUETAS_GRUPO[grupo] ?? grupo}>
              <div className="space-y-4">
                {clavesDelGrupo.map(([clave, entrada]) => {
                  // El grupo completo de WhatsApp desaparece si el toggle
                  // está apagado -- nunca se muestra deshabilitado. Ver spec
                  // §11 ("nada de mostrar ocho campos grises que no hacen
                  // nada"). La excepción es el toggle mismo, que siempre se
                  // muestra (si no, nadie podría prenderlo).
                  if (grupo === "notificaciones" && clave !== "notificaciones.usa_whatsapp" && !usaWhatsapp) {
                    return null;
                  }

                  if (entrada.tipo === "boolean") {
                    return (
                      <label key={clave} className="flex items-center gap-3 rounded-xl border border-border bg-muted p-4">
                        <input
                          type="checkbox"
                          checked={Boolean(form[clave])}
                          disabled={!puedeEditarGrupo}
                          onChange={(event) => setForm({ ...form, [clave]: event.target.checked })}
                          className="h-5 w-5 rounded border-border-strong"
                        />
                        <span>
                          <span className="block text-sm font-bold text-foreground">{entrada.etiqueta}</span>
                          <span className="block text-xs text-muted-foreground">{entrada.descripcion}</span>
                        </span>
                      </label>
                    );
                  }

                  return (
                    <label key={clave} className="space-y-2 block">
                      <span className="text-sm font-bold text-foreground">{entrada.etiqueta}</span>
                      <span className="block text-xs text-muted-foreground">{entrada.descripcion}</span>
                      <Input
                        type={entrada.sensible ? "password" : entrada.tipo === "number" ? "number" : "text"}
                        value={String(form[clave] ?? "")}
                        disabled={!puedeEditarGrupo}
                        onChange={(event) => setForm({ ...form, [clave]: event.target.value })}
                        className="h-11 rounded-xl"
                        placeholder={entrada.sensible ? "Dejar en blanco para no cambiar" : undefined}
                      />
                    </label>
                  );
                })}
              </div>
            </DashboardSection>
          );
        })}

        {puedeEditarAlgunGrupo ? (
          <div>
            <Button
              className="rounded-xl"
              disabled={guardarMutation.isPending}
              onClick={() => guardarMutation.mutate()}
            >
              {guardarMutation.isPending ? (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              ) : (
                <Save className="mr-2 h-4 w-4" />
              )}
              Guardar configuración
            </Button>
          </div>
        ) : null}

        {canRead("configuracion.facturacion") ? (
          <DashboardSection
            title="Facturación POS por tienda"
            description="Cada tienda tiene su propia conexión a POSTouch."
          >
            {resumenQuery.data.tiendas.length === 0 ? (
              <DashboardEmptyState
                title="No hay tiendas"
                description="Creá una tienda primero en Tiendas para poder configurar su facturación POS."
                icon={Settings}
              />
            ) : (
              <div className="space-y-8">
                {resumenQuery.data.tiendas.map((tienda) => (
                  <div key={tienda.tiendaId} className="border-t border-border pt-6 first:border-none first:pt-0">
                    <p className="mb-3 text-sm font-bold text-foreground">{tienda.nombre}</p>
                    <FacturacionPosConfigForm
                      tiendaId={tienda.tiendaId}
                      tiendaNombre={tienda.nombre}
                      parametros={tienda.parametros}
                      readOnly={!canWrite("configuracion.facturacion")}
                    />
                  </div>
                ))}
              </div>
            )}
          </DashboardSection>
        ) : null}
      </main>
    </div>
  );
}
