"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import QRCode from "qrcode";
import { abrirPonte, type EstadoDaTela, type FaseDaTela } from "@/lib/pdv/tela-do-cliente";
import { formatMoney } from "@/utils/formatters";

/*
  A tela do cliente.

  Recebe o estado do balcão pela ponte e só desenha. Cada fase é uma cena; a
  troca entre cenas é sempre a mesma: a que sai sobe e some, a que entra vem
  de baixo. É o ritmo de um onboarding — "preparando", "gerando", "pague
  agora" — para a pessoa acompanhar sem ler manual.

  Sem o balcão do outro lado, ela fica na vitrine: a marca respirando e as
  frases da loja passando.
*/

type Loja = {
  nome: string;
  logo: string | null;
  cor: string;
  whatsapp: string | null;
  telefone: string | null;
  endereco: string | null;
};

const CENA = {
  initial: { opacity: 0, y: 60 },
  animate: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: -60 },
  transition: { duration: 0.45, ease: [0.22, 1, 0.36, 1] as const },
};

function telefoneBonito(valor: string | null) {
  const digitos = String(valor || "").replace(/\D/g, "");
  if (digitos.length === 11) return `(${digitos.slice(0, 2)}) ${digitos.slice(2, 7)}-${digitos.slice(7)}`;
  if (digitos.length === 10) return `(${digitos.slice(0, 2)}) ${digitos.slice(2, 6)}-${digitos.slice(6)}`;
  if (digitos.length === 13 && digitos.startsWith("55")) {
    return `(${digitos.slice(2, 4)}) ${digitos.slice(4, 9)}-${digitos.slice(9)}`;
  }
  return valor || "";
}

/* Quanto falta, em mm:ss, a partir do vencimento de verdade. */
function useContagem(expiraEm: string | null | undefined) {
  /* O "agora" mora no estado e o relógio o atualiza; a conta sai do
     vencimento de verdade. O primeiro tique é imediato, para o número não
     nascer velho quando o QR chega minutos depois de a tela abrir. */
  const [agora, setAgora] = useState(() => Date.now());
  useEffect(() => {
    if (!expiraEm) return;
    const bater = () => setAgora(Date.now());
    const primeiro = window.setTimeout(bater, 0);
    const relogio = window.setInterval(bater, 500);
    return () => {
      window.clearTimeout(primeiro);
      window.clearInterval(relogio);
    };
  }, [expiraEm]);
  if (!expiraEm) return null;
  return Math.max(0, Math.floor((new Date(expiraEm).getTime() - agora) / 1000));
}

function mmss(segundos: number | null) {
  if (segundos === null) return "--:--";
  const m = Math.floor(segundos / 60);
  const s = segundos % 60;
  return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
}

function Marca({ loja, pequena }: { loja: Loja; pequena?: boolean }) {
  if (pequena) {
    return (
      <div className="tela-marca-pequena">
        {loja.logo ? (
          // eslint-disable-next-line @next/next/no-img-element
          <img src={loja.logo} alt={loja.nome} />
        ) : (
          <span>{loja.nome.slice(0, 1).toUpperCase()}</span>
        )}
      </div>
    );
  }
  return (
    <motion.div
      className="tela-marca"
      animate={{ y: [0, -10, 0], scale: [1, 1.03, 1] }}
      transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}
    >
      {loja.logo ? (
        // eslint-disable-next-line @next/next/no-img-element
        <img src={loja.logo} alt={loja.nome} />
      ) : (
        <span className="tela-marca-inicial">{loja.nome.slice(0, 1).toUpperCase()}</span>
      )}
    </motion.div>
  );
}

function Vitrine({ loja }: { loja: Loja }) {
  const frases = useMemo(() => {
    const lista: React.ReactNode[] = [
      <>
        Bem-vindo à <strong>{loja.nome}</strong>
      </>,
      <>
        Aceitamos <strong>Pix</strong>, cartão e dinheiro
      </>,
    ];
    if (loja.whatsapp) {
      lista.push(
        <>
          WhatsApp <strong>{telefoneBonito(loja.whatsapp)}</strong>
        </>
      );
    } else if (loja.telefone) {
      lista.push(
        <>
          Telefone <strong>{telefoneBonito(loja.telefone)}</strong>
        </>
      );
    }
    if (loja.endereco) lista.push(<>{loja.endereco}</>);
    lista.push(<>Obrigado por comprar com a gente</>);
    return lista;
  }, [loja]);

  const [indice, setIndice] = useState(0);
  useEffect(() => {
    const relogio = window.setInterval(() => setIndice((antes) => (antes + 1) % frases.length), 5200);
    return () => window.clearInterval(relogio);
  }, [frases.length]);

  return (
    <motion.div key="vitrine" className="tela-cena" {...CENA}>
      <Marca loja={loja} />
      <div className="tela-nome">{loja.nome}</div>
      <div className="tela-frase">
        <AnimatePresence mode="wait">
          <motion.div
            key={indice}
            initial={{ opacity: 0, y: 24 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -24 }}
            transition={{ duration: 0.5, ease: "easeOut" }}
          >
            {frases[indice]}
          </motion.div>
        </AnimatePresence>
      </div>
    </motion.div>
  );
}

function Conta({ loja, estado }: { loja: Loja; estado: EstadoDaTela }) {
  const fim = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    fim.current?.scrollIntoView({ block: "end", behavior: "smooth" });
  }, [estado.itens.length]);

  return (
    <motion.div key="conta" className="tela-conta" {...CENA}>
      <div className="flex min-h-0 flex-col">
        <div className="tela-conta-cabeca">
          <Marca loja={loja} pequena />
          <div className="tela-conta-titulo">Sua compra</div>
        </div>
        <div className="tela-itens">
          <div className="tela-itens-rolagem">
            <AnimatePresence initial={false}>
              {estado.itens.map((item) => (
                <motion.div
                  key={item.id}
                  className="tela-item"
                  layout
                  initial={{ opacity: 0, x: -40 }}
                  animate={{ opacity: 1, x: 0 }}
                  exit={{ opacity: 0, x: 40 }}
                  transition={{ duration: 0.3, ease: "easeOut" }}
                >
                  <div className="tela-item-qtd">{item.quantidade}×</div>
                  <div className="min-w-0">
                    <div className="tela-item-nome">{item.titulo}</div>
                    {item.medida || item.detalhe ? (
                      <div className="tela-item-detalhe">{[item.medida, item.detalhe].filter(Boolean).join(" · ")}</div>
                    ) : null}
                  </div>
                  <div className="tela-item-total">{formatMoney(item.total)}</div>
                </motion.div>
              ))}
            </AnimatePresence>
            <div ref={fim} />
          </div>
        </div>
      </div>
      <div className="tela-total">
        <div className="tela-total-rotulo">Total</div>
        <motion.div
          key={estado.total}
          className="tela-total-valor"
          initial={{ scale: 1.06, opacity: 0.6 }}
          animate={{ scale: 1, opacity: 1 }}
          transition={{ duration: 0.25 }}
        >
          {formatMoney(estado.total)}
        </motion.div>
        {estado.desconto > 0.009 ? (
          <div className="tela-total-linha">
            Subtotal {formatMoney(estado.subtotal)} · Desconto <strong>−{formatMoney(estado.desconto)}</strong>
          </div>
        ) : null}
        {estado.cliente ? <div className="tela-cliente">{estado.cliente}</div> : null}
      </div>
    </motion.div>
  );
}

function Passo({ chave, titulo, sub }: { chave: string; titulo: string; sub: string }) {
  return (
    <motion.div key={chave} className="tela-cena" {...CENA}>
      <div className="tela-anel" />
      <div className="tela-passo-titulo">{titulo}</div>
      <div className="tela-passo-sub">{sub}</div>
    </motion.div>
  );
}

function Pagar({ estado }: { estado: EstadoDaTela }) {
  const pix = estado.pix;
  const restante = useContagem(pix?.expiraEm);
  const [svg, setSvg] = useState<{ codigo: string; desenho: string } | null>(null);

  /* O QR é desenhado aqui, em vetor, para ficar nítido em qualquer tamanho de
     tela. O base64 do provedor é o plano B. O desenho fica guardado junto com
     o código que o gerou: trocou o código, o desenho velho deixa de valer. */
  useEffect(() => {
    let cancelado = false;
    const codigo = pix?.qrCode;
    if (!codigo) return;
    QRCode.toString(codigo, { type: "svg", margin: 0, errorCorrectionLevel: "M" })
      .then((desenho) => {
        if (!cancelado) setSvg({ codigo, desenho });
      })
      .catch(() => undefined);
    return () => {
      cancelado = true;
    };
  }, [pix?.qrCode]);
  const desenhoDoQr = svg && svg.codigo === pix?.qrCode ? svg.desenho : null;

  const urgente = restante !== null && restante <= 60;
  const venceu = restante === 0;

  return (
    <motion.div key="pagar" className="tela-cena" {...CENA}>
      <div className="tela-pagar">
        <div className="tela-qr">
          {desenhoDoQr ? (
            <div dangerouslySetInnerHTML={{ __html: desenhoDoQr }} />
          ) : pix?.qrCodeBase64 ? (
            // eslint-disable-next-line @next/next/no-img-element
            <img
              src={pix.qrCodeBase64.startsWith("data:") ? pix.qrCodeBase64 : `data:image/png;base64,${pix.qrCodeBase64}`}
              alt="QR Code do Pix"
            />
          ) : null}
        </div>
        <div>
          <div className="tela-passo-titulo">Pague agora</div>
          <div className="tela-pagar-valor">{formatMoney(pix?.valor || estado.total)}</div>
          <div className="tela-pagar-passos">
            <div>
              <span>1</span>Abra o app do seu banco
            </div>
            <div>
              <span>2</span>Escolha pagar com Pix e leia o código
            </div>
            <div>
              <span>3</span>Confirme — a tela avisa quando cair
            </div>
          </div>
          <div className={`tela-relogio ${urgente ? "tela-relogio-urgente" : ""}`}>
            {venceu ? (
              <>Este código venceu</>
            ) : (
              <>
                <span className="tela-relogio-rotulo">vale por</span>
                {mmss(restante)}
              </>
            )}
          </div>
        </div>
      </div>
    </motion.div>
  );
}

function Confirmado({ estado }: { estado: EstadoDaTela }) {
  const troco = Number(estado.venda?.troco || 0);
  return (
    <motion.div key="aprovado" className="tela-cena" {...CENA}>
      <svg className="tela-check" viewBox="0 0 100 100" aria-hidden="true">
        <circle cx="50" cy="50" r="48" />
        <path d="M30 52 L44 66 L72 36" />
      </svg>
      <div className="tela-passo-titulo">Pagamento confirmado</div>
      <div className="tela-passo-sub">
        {estado.venda?.numero ? `Pedido #${estado.venda.numero} · ` : ""}
        Obrigado pela preferência!
      </div>
      {troco > 0.009 ? (
        <div className="tela-relogio" style={{ marginTop: "4vmin" }}>
          <span className="tela-relogio-rotulo">seu troco</span>
          {formatMoney(troco)}
        </div>
      ) : null}
      {estado.venda?.entrega?.qr ? (
        <div style={{ marginTop: "4vmin", display: "flex", flexDirection: "column", alignItems: "center", gap: "1.5vmin" }}>
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src={estado.venda.entrega.qr} alt="QR code do seu produto digital" style={{ width: "34vmin", height: "34vmin", background: "#fff", borderRadius: "2vmin", padding: "1.5vmin" }} />
          <div className="tela-passo-sub">Aponte a câmera do celular para receber o seu produto digital</div>
        </div>
      ) : null}
    </motion.div>
  );
}

function Recado({ chave, titulo, sub }: { chave: string; titulo: string; sub: string }) {
  return (
    <motion.div key={chave} className="tela-cena" {...CENA}>
      <div className="tela-passo-titulo">{titulo}</div>
      <div className="tela-passo-sub">{sub}</div>
    </motion.div>
  );
}

function fundoDaFase(fase: FaseDaTela) {
  if (fase === "aprovado") return "tela-verde";
  if (fase === "cancelado" || fase === "expirado") return "tela-vermelha";
  return "";
}

export default function TelaDoClientePage() {
  const [loja, setLoja] = useState<Loja | null>(null);
  const [tenantId, setTenantId] = useState<string | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const [estado, setEstado] = useState<EstadoDaTela | null>(null);
  /* Sem notícia do balcão por um tempo, a tela volta à vitrine sozinha: um
     total esquecido na tela depois que o caixa fechou o sistema é pior do
     que nenhum total. */
  const ultimaNoticia = useRef(0);

  useEffect(() => {
    let cancelado = false;
    fetch("/api/pdv/tela", { cache: "no-store" })
      .then(async (resposta) => {
        const dados = (await resposta.json().catch(() => null)) as
          | { ok?: boolean; error?: string; tenantId?: string; loja?: Loja }
          | null;
        if (cancelado) return;
        if (!resposta.ok || !dados?.ok || !dados.tenantId || !dados.loja) {
          setErro(dados?.error || "Não foi possível abrir a tela do cliente.");
          return;
        }
        setTenantId(dados.tenantId);
        setLoja(dados.loja);
      })
      .catch(() => {
        if (!cancelado) setErro("Não foi possível abrir a tela do cliente.");
      });
    return () => {
      cancelado = true;
    };
  }, []);

  useEffect(() => {
    if (!tenantId) return;
    const ponte = abrirPonte(tenantId, (mensagem) => {
      if (mensagem.evento !== "estado") return;
      ultimaNoticia.current = Date.now();
      setEstado(mensagem.estado);
    });
    /* Chegando, pede o estado atual: o balcão responde na hora. */
    const pedir = window.setTimeout(() => ponte.enviar({ evento: "ola", origem: "tela" }), 400);

    const vigia = window.setInterval(() => {
      if (ultimaNoticia.current && Date.now() - ultimaNoticia.current > 45000) {
        setEstado(null);
        ultimaNoticia.current = 0;
      }
    }, 5000);

    return () => {
      window.clearTimeout(pedir);
      window.clearInterval(vigia);
      ponte.fechar();
    };
  }, [tenantId]);

  /* Tela cheia com um clique: é o que se faz no segundo monitor. */
  useEffect(() => {
    const aoClicar = () => {
      const raiz = document.documentElement;
      if (!document.fullscreenElement && raiz.requestFullscreen) {
        raiz.requestFullscreen().catch(() => undefined);
      }
    };
    window.addEventListener("click", aoClicar);
    return () => window.removeEventListener("click", aoClicar);
  }, []);

  if (erro) {
    return <div className="tela-desligada">{erro}</div>;
  }
  if (!loja) {
    return <div className="tela-desligada">Abrindo a tela do cliente…</div>;
  }

  const fase: FaseDaTela = estado?.fase || "ocioso";
  const cenaOciosa = fase === "ocioso" || (fase === "conta" && !estado?.itens.length);

  return (
    <div className={`tela ${fundoDaFase(fase)}`} style={{ "--cor": loja.cor } as React.CSSProperties}>
      <div className="tela-luz tela-luz-a" />
      <div className="tela-luz tela-luz-b" />
      {/* Sem `mode="wait"`: a cena nova entra enquanto a velha sai (as duas
          ocupam a tela inteira, então viram um cruzamento). Esperar a saída
          travava a tela quando a janela estava escondida — o navegador congela
          a animação de quem não está à vista, e a cena nova nunca chegava. */}
      <AnimatePresence initial={false}>
        {cenaOciosa ? (
          <Vitrine key="vitrine" loja={loja} />
        ) : fase === "conta" && estado ? (
          <Conta key="conta" loja={loja} estado={estado} />
        ) : fase === "preparando" ? (
          <Passo key="preparando" chave="preparando" titulo="Preparando pagamento" sub="Só um instante…" />
        ) : fase === "gerando" ? (
          <Passo key="gerando" chave="gerando" titulo="Gerando QR Code" sub="Pedindo o Pix ao banco" />
        ) : fase === "pagar" && estado ? (
          <Pagar key="pagar" estado={estado} />
        ) : fase === "aprovado" && estado ? (
          <Confirmado key="aprovado" estado={estado} />
        ) : fase === "expirado" ? (
          <Recado key="expirado" chave="expirado" titulo="O código venceu" sub="Peça um novo Pix ao atendente" />
        ) : (
          <Recado key="cancelado" chave="cancelado" titulo="Pagamento cancelado" sub="Tudo bem — vamos de outro jeito" />
        )}
      </AnimatePresence>
      <div className="tela-rodape">{loja.nome}</div>
    </div>
  );
}
