"use client";

import type React from "react";
import { useCallback, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { ArrowRight, Check, X } from "lucide-react";

/**
 * O recado que abre no meio da tela ao entrar no sistema.
 *
 * Metade imagem, metade cor com o texto e, se o dono quiser, um botão. A
 * decisão de aparecer é toda do servidor: aqui só chega o que esta pessoa
 * ainda tem para ver.
 *
 * Quando o aviso pede ciência, o X e o clique fora param de fechar. A única
 * saída é marcar a caixa, e essa marcação vira registro com data, empresa e o
 * texto exato que estava escrito.
 */

type Popup = {
  id: string;
  title: string;
  message: string | null;
  image_url: string | null;
  image_url_mobile: string | null;
  image_side: "left" | "right";
  background_color: string;
  text_color: string;
  cta_label: string | null;
  cta_url: string | null;
  cta_new_tab: boolean;
  require_ack: boolean;
  ack_label: string;
};

/* Preto ou branco em cima da cor escolhida, pelo brilho dela. Serve para o
   fundo do botão, que usa a cor do texto: sem isso, texto claro sobre botão
   claro some. */
function contrasteSobre(hex: string) {
  const limpo = String(hex || "").replace("#", "");
  const cheio = limpo.length === 3 ? limpo.split("").map((c) => c + c).join("") : limpo;
  if (cheio.length !== 6) return "#0F172A";
  const r = parseInt(cheio.slice(0, 2), 16);
  const g = parseInt(cheio.slice(2, 4), 16);
  const b = parseInt(cheio.slice(4, 6), 16);
  const brilho = (r * 299 + g * 587 + b * 114) / 1000;
  return brilho > 160 ? "#0F172A" : "#FFFFFF";
}

/** Avisa o servidor sem segurar a tela. Falha aqui só faz o aviso voltar. */
function registrar(popupId: string, acao: "abriu" | "fechou" | "ciente") {
  void fetch("/api/system-popups", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ popup_id: popupId, acao }),
  }).catch(() => {});
}

export function SystemPopupHost() {
  const [fila, setFila] = useState<Popup[]>([]);
  const [marcado, setMarcado] = useState(false);
  const [anunciado, setAnunciado] = useState("");

  useEffect(() => {
    let vivo = true;
    (async () => {
      try {
        const resposta = await fetch("/api/system-popups", { cache: "no-store" });
        if (!resposta.ok) return;
        const corpo = (await resposta.json().catch(() => null)) as { popups?: Popup[] } | null;
        if (vivo && Array.isArray(corpo?.popups)) setFila(corpo.popups);
      } catch {
        /* Recado que não carrega não pode atrapalhar quem entrou para trabalhar. */
      }
    })();
    return () => {
      vivo = false;
    };
  }, []);

  const atual = fila[0] ?? null;
  const travado = Boolean(atual?.require_ack);

  /* A abertura é registrada uma vez por aviso. Ajuste de estado durante a
     renderização, e não efeito: é o padrão da casa e evita o quadro em que o
     aviso aparece antes de o servidor saber que apareceu. */
  if (atual && anunciado !== atual.id) {
    setAnunciado(atual.id);
    setMarcado(false);
    registrar(atual.id, "abriu");
  }

  const sair = useCallback(
    (acao: "fechou" | "ciente") => {
      const fechando = fila[0];
      if (!fechando) return;
      setFila((antes) => antes.slice(1));
      setMarcado(false);
      registrar(fechando.id, acao);
    },
    [fila]
  );

  const tentarFechar = useCallback(() => {
    if (travado) return;
    sair("fechou");
  }, [travado, sair]);

  useEffect(() => {
    if (!atual) return;
    const aoTeclar = (evento: KeyboardEvent) => {
      if (evento.key === "Escape") tentarFechar();
    };
    window.addEventListener("keydown", aoTeclar);
    /* A página atrás não rola enquanto o recado está aberto. */
    const rolagemAntes = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", aoTeclar);
      document.body.style.overflow = rolagemAntes;
    };
  }, [atual, tentarFechar]);

  /* `document` só existe no navegador. A fila nasce vazia, então o servidor e a
     primeira renderização do cliente concordam: os dois devolvem nada. */
  if (!atual || typeof document === "undefined") return null;

  const temImagem = Boolean(atual.image_url);
  const arteDoCelular = String(atual.image_url_mobile || "").trim();
  const temBotao = Boolean(atual.cta_label && atual.cta_url);
  const corDoRotuloDoBotao = contrasteSobre(atual.text_color);

  /* O que sobra em volta da imagem leva a cor do popup: com `contain` a foto
     nunca é cortada, e sem essa cor apareceria uma faixa cinza do lado. */
  /* Duas artes, duas proporções. No computador a metade da imagem é 1:2 em pé;
     no celular ela vira uma faixa 4:3 deitada. `<picture>` deixa o navegador
     escolher e baixar só uma, no mesmo ponto de corte do CSS.

     Sem a arte de celular, entra a saída de antes: a arte do computador
     inteira, centralizada sobre uma cópia desfocada dela mesma, que preenche a
     faixa sem cortar nada. */
  const imagem = temImagem ? (
    <div className="ktl-popup-imagem" style={{ background: atual.background_color }}>
      {arteDoCelular ? null : (
        /* eslint-disable-next-line @next/next/no-img-element */
        <img className="ktl-popup-desfoque" src={atual.image_url as string} alt="" aria-hidden="true" />
      )}
      {/* Dentro de <picture> a regra do `next/image` nao reclama, e nem devia:
          aqui o ponto e justamente escolher o arquivo pela largura da tela. */}
      <picture>
        {arteDoCelular ? <source media="(max-width: 560px)" srcSet={arteDoCelular} /> : null}
        <img className="ktl-popup-arte" src={atual.image_url as string} alt="" />
      </picture>
    </div>
  ) : null;

  const conteudo = (
    <div className="ktl-popup-texto" style={{ background: atual.background_color, color: atual.text_color }}>
      <h2 className="ktl-popup-titulo">{atual.title}</h2>
      {atual.message ? <p className="ktl-popup-mensagem">{atual.message}</p> : null}

      {/* No aviso travado a ordem e a propria instrucao: le o texto, abre o
          boletim, confirma que leu, entra. O link vinha ao lado do "Continuar",
          e ali ele parecia alternativa ao botao em vez de passo anterior. */}
      {travado ? (
        <>
          {temBotao ? (
            <a
              className="ktl-popup-atalho"
              href={atual.cta_url as string}
              target={atual.cta_new_tab ? "_blank" : undefined}
              rel={atual.cta_new_tab ? "noopener noreferrer" : undefined}
            >
              <span>{atual.cta_label}</span>
              <ArrowRight size={15} strokeWidth={2.5} aria-hidden="true" />
            </a>
          ) : null}

          <label
            className="ktl-popup-ciente"
            style={{ ["--ktl-popup-fundo" as string]: atual.background_color } as React.CSSProperties}
          >
            <input
              type="checkbox"
              checked={marcado}
              onChange={(evento) => setMarcado(evento.target.checked)}
            />
            <span className="ktl-popup-ciente-caixa" aria-hidden="true">
              {marcado ? <Check size={13} strokeWidth={3} /> : null}
            </span>
            <span>{atual.ack_label}</span>
          </label>

          <button
            type="button"
            className="ktl-popup-botao ktl-popup-botao-largo"
            disabled={!marcado}
            onClick={() => sair("ciente")}
            style={{ background: atual.text_color, color: corDoRotuloDoBotao }}
          >
            Continuar
          </button>
        </>
      ) : temBotao ? (
        <a
          className="ktl-popup-botao"
          href={atual.cta_url as string}
          target={atual.cta_new_tab ? "_blank" : undefined}
          rel={atual.cta_new_tab ? "noopener noreferrer" : undefined}
          onClick={() => sair("fechou")}
          style={{ background: atual.text_color, color: corDoRotuloDoBotao }}
        >
          {atual.cta_label}
        </a>
      ) : null}
    </div>
  );

  return createPortal(
    <div className="ktl-popup-fundo" role="presentation" onClick={tentarFechar}>
      <div
        className={`ktl-popup ${temImagem ? "" : "ktl-popup-so-texto"}${arteDoCelular ? " ktl-popup-com-arte-movel" : ""}`}
        role="dialog"
        aria-modal="true"
        aria-label={atual.title}
        onClick={(evento) => evento.stopPropagation()}
      >
        {travado ? null : (
          <button type="button" className="ktl-popup-fechar" onClick={tentarFechar} aria-label="Fechar">
            <X size={17} />
          </button>
        )}
        {atual.image_side === "right" ? (
          <>
            {conteudo}
            {imagem}
          </>
        ) : (
          <>
            {imagem}
            {conteudo}
          </>
        )}
      </div>
    </div>,
    document.body
  );
}

export default SystemPopupHost;
