import { Link, router, usePage } from "@inertiajs/react";
import { AlertTriangle, Info, OctagonAlert } from "lucide-react";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { t } from "@/lib/i18n";
import { noticeMessage, noticeTitle } from "@/lib/notices";
import type { Notice } from "@/types/inertia";

const ICONS = {
  info: Info,
  warning: AlertTriangle,
  error: OctagonAlert,
} as const;

/*
  Los tres tonos salen de tokens y no de una escala fija de Tailwind. Un
  `text-amber-900` sobre el fondo oscuro es texto casi negro sobre casi negro:
  se leía bien porque hasta ahora el fondo era siempre claro. El tono lo pone
  `Alert` con su variante; acá sólo queda heredarlo.
*/
const TEXT_COLORS = {
  info: "text-foreground",
  warning: "",
  error: "",
} as const;

/** El tono del aviso es el mismo que usa su estado en el resto del producto. */
const TONES = {
  info: "default",
  warning: "attention",
  error: "critical",
} as const;

/**
 * El estado de la cuenta: una luz en la barra superior, no un bloque en cada
 * pantalla.
 *
 * **La ausencia del indicador es la señal de salud.** Con la cuenta sana acá no
 * hay nada, y ese vacío es lo que se aprende a mirar de reojo; un bloque rojo de
 * 120 px clavado arriba del contenido se aprende a ignorar en dos días, que es
 * exactamente lo que le había pasado.
 *
 * **Está en todas las pantallas y sin excepciones**, incluida la que resuelve el
 * problema. La versión anterior se suprimía sobre su propia pantalla de destino
 * —tenía dos funciones y sus dos docstrings para decidirlo— porque un bloque
 * intrusivo tenía que callarse donde estorbaba. Un icono no estorba en ninguna
 * parte, así que la regla se cae sola: una luz de estado que se apaga en una
 * pantalla es una luz que miente.
 *
 * **La distinción no la porta el color** (RT-04): van el icono y la palabra, y
 * el nombre accesible dice cuántas cosas hay. Un glifo suelto en rojo no lo lee
 * quien no distingue el rojo, y quien nunca vio el estado sano tampoco sabe si
 * es un botón o un adorno.
 *
 * Lo que **no** hace es reemplazar la honestidad del dato. El bloque existía
 * para impedir que alguien leyera cifras viejas como si fueran de hoy; encogerlo
 * saca esa protección salvo que cada pantalla diga por su cuenta que lo que
 * muestra quedó viejo. Eso es R-F y lo resuelve `DomainIdentity`.
 */
export function AccountStatus() {
  const { account } = usePage().props;
  const notices = account?.notices ?? [];

  const [open, setOpen] = useState(false);

  // Seguir un aviso navega, y sin esto el panel queda abierto sobre la pantalla
  // nueva: Inertia no desmonta el armazón al cambiar de página.
  useEffect(() => router.on("navigate", () => setOpen(false)), []);

  if (notices.length === 0) return null;

  const critical = notices.some((notice) => notice.level === "error");
  const Icon = critical ? OctagonAlert : AlertTriangle;

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button size="sm" variant={critical ? "critical" : "destructive"}>
          <Icon aria-hidden />
          {t("account.review", { count: notices.length })}
        </Button>
      </PopoverTrigger>

      {/*
        Ancho propio: los 288 px del registro alcanzan para una frase y estos
        avisos traen título, motivo y destino. El tope de alto es para que una
        cuenta con muchos dominios caídos no empuje la lista fuera de la
        pantalla.
      */}
      <PopoverContent align="end" className="max-h-[70vh] w-96 overflow-y-auto">
        {notices.map((notice) => (
          <NoticeAlert key={notice.code} notice={notice} />
        ))}
      </PopoverContent>
    </Popover>
  );
}

/**
 * Un aviso dentro de la lista.
 *
 * Va como `Alert` y no como `NoticeItem` —la fila que usan el panel del tablero
 * y la pantalla de avisos— porque esta lista **mezcla niveles**: lo que impide
 * operar y lo que puede esperar tienen que distinguirse sin leerlos, y la
 * superficie teñida es lo que hace esa diferencia en el resto del producto.
 * `NoticeItem` no tiene tono de gravedad y agregárselo lo volvería otra cosa.
 */
function NoticeAlert({ notice }: { notice: Notice }) {
  const Icon = ICONS[notice.level] ?? Info;

  return (
    <Link href={notice.action_path}>
      <Alert variant={TONES[notice.level] ?? "default"}>
        <Icon />
        <AlertTitle>{noticeTitle(notice)}</AlertTitle>
        <AlertDescription className={cn("flex flex-col items-start gap-2", TEXT_COLORS[notice.level])}>
          <span>{noticeMessage(notice)}</span>
        </AlertDescription>
      </Alert>
    </Link>
  );
}
