"use client";

import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";

/*
  A faixa de aviso do topo — a mesma que o lojista já configura no catálogo
  (Catálogo › Marketing): texto com **destaque**, relógio de contagem, cupom
  que copia com um toque, botão com link e a escolha de acompanhar ou não a
  rolagem (quem decide onde ela entra é o shell).

  O desenho é o da referência: faixa #121212, texto branco em Montserrat
  15/500 com espaçamento largo (11 px no celular, podendo quebrar em duas
  linhas) e as mensagens se revezando a cada 3,5 s — a que sai desliza para a
  esquerda com desfoque, a próxima entra pela direita.

  MAIS DE UMA MENSAGEM: o lojista separa as frases no próprio texto do aviso,
  uma por linha OU com " | " entre elas. Exemplo:
    "Frete grátis acima de R$ 299 | **5% OFF** no Pix | Troca fácil em 7 dias"
  Com cupom escolhido, a frase do cupom entra na roda como mais uma mensagem,
  e o código vira um botão sublinhado que copia ("Copiado!").

  Cor: a faixa respeita a cor que o lojista escolheu. As cores que o painel
  grava quando ninguém mexeu (#111827 no fundo, #FFFFFF no texto, #FB7185 no
  selo) contam como "não escolhida", e aí vale a da referência.

  O código é da Boutique — nada aqui é importado dos outros templates nem
  exportado para eles. O que se repete é a configuração, não o arquivo.
*/

export type BoutiqueCupomDoAviso = {
  code?: string | null;
  type?: string | null;
  value?: number | null;
};

const TROCA_A_CADA = 3500;
const SAIDA = 450;
const PAUSA_ENTRE = 180;

function corValida(valor: string | null | undefined) {
  const bruto = String(valor || "").trim();
  const hex = bruto.startsWith("#") ? bruto.slice(1) : bruto;
  if (/^[0-9a-f]{6}$/i.test(hex)) return `#${hex.toLowerCase()}`;
  if (/^[0-9a-f]{3}$/i.test(hex)) {
    return `#${hex
      .toLowerCase()
      .split("")
      .map((c) => c + c)
      .join("")}`;
  }
  return null;
}

/* A cor que o painel grava sozinho não é escolha do lojista. */
function corEscolhida(valor: string | null | undefined, padraoDoPainel: string) {
  const cor = corValida(valor);
  return cor && cor !== padraoDoPainel ? cor : null;
}

function comAlfa(cor: string, alfa: number) {
  const hex = cor.replace("#", "");
  const r = parseInt(hex.slice(0, 2), 16);
  const g = parseInt(hex.slice(2, 4), 16);
  const b = parseInt(hex.slice(4, 6), 16);
  return `rgba(${r}, ${g}, ${b}, ${alfa})`;
}

function comDestaque(texto: string, chave: string) {
  return texto
    .split(/(\*\*[^*]+\*\*)/g)
    .filter(Boolean)
    .map((parte, indice) =>
      parte.startsWith("**") && parte.endsWith("**") ? (
        <strong key={`${chave}-forte-${indice}`} className="font-bold">
          {parte.slice(2, -2)}
        </strong>
      ) : (
        <span key={`${chave}-normal-${indice}`}>{parte}</span>
      )
    );
}

/** As mensagens do aviso: uma por linha ou separadas por " | ". */
export function mensagensDoAviso(texto: string | null | undefined): string[] {
  return String(texto || "")
    .split(/\r?\n|\s+\|\s+/)
    .map((parte) => parte.trim())
    .filter(Boolean);
}

/* O botão pode apontar para um produto ou categoria do próprio catálogo. */
function enderecoDoBotao(url: string | null | undefined, slug: string) {
  const bruto = String(url || "").trim();
  if (!bruto) return "";
  const produto = bruto.match(/^catalog:\/\/product\/([^/?#]+)/i);
  if (produto?.[1]) return `/${slug}/p/${decodeURIComponent(produto[1])}`;
  const categoria = bruto.match(/^catalog:\/\/(?:category|subcategory)\/([^/?#]+)/i);
  if (categoria?.[1]) return `/${slug}/c/${decodeURIComponent(categoria[1])}`;
  return bruto;
}

function pedacosDaContagem(fim: string, agora: number) {
  const alvo = new Date(fim).getTime();
  const segundos = !Number.isFinite(alvo) || agora <= 0 ? 0 : Math.floor(Math.max(0, alvo - agora) / 1000);
  const doisDigitos = (n: number) => String(n).padStart(2, "0");
  return [
    { rotulo: "d", valor: doisDigitos(Math.floor(segundos / 86400)) },
    { rotulo: "h", valor: doisDigitos(Math.floor((segundos % 86400) / 3600)) },
    { rotulo: "m", valor: doisDigitos(Math.floor((segundos % 3600) / 60)) },
    { rotulo: "s", valor: doisDigitos(segundos % 60) },
  ];
}

type Fase = "visivel" | "saindo" | "antes";

export function BoutiqueAviso({
  slug,
  ligado,
  texto,
  corDeFundo,
  corDoTexto,
  botaoRotulo,
  botaoUrl,
  cupom,
  mostrarSelo,
  corDoSelo,
  contagemLigada,
  contagemAte,
}: {
  slug: string;
  ligado?: boolean | null;
  texto?: string | null;
  corDeFundo?: string | null;
  corDoTexto?: string | null;
  botaoRotulo?: string | null;
  botaoUrl?: string | null;
  cupom?: BoutiqueCupomDoAviso | null;
  mostrarSelo?: boolean | null;
  corDoSelo?: string | null;
  contagemLigada?: boolean | null;
  contagemAte?: string | null;
}) {
  const [agora, setAgora] = useState(0);
  const [copiado, setCopiado] = useState(false);
  const [indice, setIndice] = useState(0);
  const [fase, setFase] = useState<Fase>("visivel");
  const [parado, setParado] = useState(false);
  const relogios = useRef<number[]>([]);

  const temContagem = Boolean(contagemLigada && contagemAte);
  const fimDaContagem = new Date(String(contagemAte || "")).getTime();
  const codigo = String(cupom?.code || "").trim();
  const temCupom = Boolean(codigo);
  const codigoCopia = temCupom && mostrarSelo !== false;

  /* A roda de mensagens: as frases do texto e, com cupom, a frase dele. */
  const mensagens = useMemo(() => {
    const lista: Array<{ chave: string; conteudo: "texto" | "cupom"; frase: string }> = mensagensDoAviso(texto).map(
      (frase, i) => ({ chave: `t${i}`, conteudo: "texto", frase })
    );
    if (temCupom) lista.push({ chave: "cupom", conteudo: "cupom", frase: "" });
    return lista;
  }, [texto, temCupom]);
  const total = mensagens.length;
  const atual = total ? mensagens[indice % total] : null;

  /* O relógio só anda quando existe contagem para mostrar. E começa fora da
     primeira renderização: o servidor não tem a mesma hora do navegador. */
  useEffect(() => {
    if (!temContagem) return;
    const marcar = () => setAgora(Date.now());
    const primeiro = window.setTimeout(marcar, 0);
    const relogio = window.setInterval(marcar, 1000);
    return () => {
      window.clearTimeout(primeiro);
      window.clearInterval(relogio);
    };
  }, [temContagem]);

  useEffect(() => {
    if (!copiado) return;
    const volta = window.setTimeout(() => setCopiado(false), 1500);
    return () => window.clearTimeout(volta);
  }, [copiado]);

  /* A troca: sai (desliza e desfoca), espera um instante, entra a próxima.
     Para com o mouse em cima — é quando a pessoa está lendo ou indo copiar
     o cupom. Com movimento reduzido, só troca o texto. */
  useEffect(() => {
    if (total <= 1 || parado) return;
    const reduzido =
      typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
    const ciclo = window.setInterval(() => {
      if (reduzido) {
        setIndice((i) => (i + 1) % total);
        return;
      }
      setFase("saindo");
      relogios.current.push(
        window.setTimeout(() => {
          setIndice((i) => (i + 1) % total);
          setFase("antes");
          relogios.current.push(window.setTimeout(() => setFase("visivel"), PAUSA_ENTRE));
        }, SAIDA)
      );
    }, TROCA_A_CADA);
    return () => {
      window.clearInterval(ciclo);
      relogios.current.forEach((r) => window.clearTimeout(r));
      relogios.current = [];
      setFase("visivel");
    };
  }, [total, parado]);

  const fundo = corEscolhida(corDeFundo, "#111827") || "#121212";
  const frente = corEscolhida(corDoTexto, "#ffffff") || "#ffffff";
  const corDoCodigo = corEscolhida(corDoSelo, "#fb7185");
  const contagem = useMemo(
    () => (temContagem ? pedacosDaContagem(String(contagemAte || ""), agora) : []),
    [temContagem, contagemAte, agora]
  );
  const endereco = enderecoDoBotao(botaoUrl, slug);
  const botao = Boolean(String(botaoRotulo || "").trim() && endereco);

  const temConteudo = Boolean(total || temContagem || botao);
  if (!ligado || !temConteudo) return null;

  const copiarCupom = async () => {
    if (!codigo || typeof navigator === "undefined" || !navigator.clipboard) return;
    try {
      await navigator.clipboard.writeText(codigo);
      setCopiado(true);
    } catch {
      /* Sem permissão de área de transferência o código continua à vista,
         que é o que o cliente precisa para digitar. */
    }
  };

  const codigoNaFrase: ReactNode = codigoCopia ? (
    <button
      type="button"
      onClick={copiarCupom}
      title="Copiar o cupom"
      className="font-bold underline decoration-1 underline-offset-[3px] transition-opacity hover:opacity-80"
      style={corDoCodigo ? { color: corDoCodigo } : undefined}
    >
      {copiado ? "Copiado!" : codigo}
    </button>
  ) : (
    <strong className="font-bold">{codigo}</strong>
  );

  const fraseDoCupom = (() => {
    if (!temCupom) return null;
    const tipo = cupom?.type;
    const valor = Number(cupom?.value || 0);
    const ganho =
      tipo === "free_shipping"
        ? "frete grátis"
        : tipo === "percent"
          ? `${valor.toLocaleString("pt-BR")}% OFF`
          : `${valor.toLocaleString("pt-BR", { style: "currency", currency: "BRL" })} OFF`;
    return (
      <>
        {tipo === "free_shipping" ? "Frete grátis" : ganho} em todo o site com o cupom {codigoNaFrase}
      </>
    );
  })();

  /* Texto que termina em "cupom" ("…com o cupom") conta com o selo do código
     logo depois, como os outros temas desenham: aqui o código entra no fim
     da própria frase, senão a frase fica pendurada na roda. */
  const fraseDeTexto = (frase: string, chave: string): ReactNode =>
    temCupom && /cupom[\s:]*$/i.test(frase) ? (
      <>
        {comDestaque(frase, chave)} {codigoNaFrase}
      </>
    ) : (
      comDestaque(frase, chave)
    );
  const conteudoAtual =
    atual?.conteudo === "cupom" ? fraseDoCupom : atual ? fraseDeTexto(atual.frase, atual.chave) : null;

  /* A promoção acabou: o relógio zerado sai da faixa (antes da primeira
     leitura do relógio, `agora` é 0 e ele fica, para não pular na tela). */
  const contagemAcabou = agora > 0 && Number.isFinite(fimDaContagem) && fimDaContagem <= agora;
  const relogio = temContagem && !contagemAcabou ? (
    <span className="inline-flex shrink-0 items-center gap-1 tabular-nums" suppressHydrationWarning>
      {contagem.map((parte) => (
        <span key={parte.rotulo} className="inline-flex items-baseline">
          <span
            className="inline-flex h-[22px] min-w-[24px] items-center justify-center px-1 text-[11px] font-semibold md:h-6 md:text-[12px]"
            style={{ backgroundColor: comAlfa(frente, 0.12) }}
          >
            {parte.valor}
          </span>
          <span className="ml-[2px] text-[9px] font-medium uppercase opacity-75">{parte.rotulo}</span>
        </span>
      ))}
    </span>
  ) : null;

  const linkDoBotao = botao ? (
    <a
      href={endereco}
      className="shrink-0 border-b pb-[2px] text-[10px] font-bold uppercase tracking-[0.12em] transition-opacity hover:opacity-80 md:text-[11px]"
      style={{ borderColor: comAlfa(frente, 0.7) }}
    >
      {String(botaoRotulo || "").trim()} →
    </a>
  ) : null;

  return (
    <div
      data-bq-aviso=""
      className="relative overflow-hidden"
      style={{ backgroundColor: fundo, color: frente }}
      onMouseEnter={() => setParado(true)}
      onMouseLeave={() => setParado(false)}
      onFocus={() => setParado(true)}
      onBlur={() => setParado(false)}
    >
      <div className="mx-auto flex min-h-[54px] w-full max-w-[1700px] flex-col items-center justify-center gap-1 px-4 py-[6px] md:min-h-[52px] md:flex-row md:gap-4 md:px-[60px] md:py-[10px]">
        {conteudoAtual ? (
          <div className="flex min-h-[26px] w-full min-w-0 items-center justify-center md:min-h-[32px] md:w-auto">
            <p
              key={atual?.chave}
              data-fase={fase}
              aria-live="polite"
              className="bq-aviso-frase text-center text-[11px] font-medium leading-[1.2] tracking-[0.03em] md:text-[15px] md:tracking-[0.08em]"
            >
              {conteudoAtual}
            </p>
          </div>
        ) : null}

        {relogio || linkDoBotao ? (
          <div className="flex items-center justify-center gap-3">
            {relogio}
            {linkDoBotao}
          </div>
        ) : null}
      </div>
    </div>
  );
}
