"use client";

import { useCallback, useEffect, useRef, useState, useSyncExternalStore, type ReactNode } from "react";
import { createPortal } from "react-dom";
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
import {
  BadgeCheck,
  Building2,
  CheckCircle2,
  Clock3,
  FlaskConical,
  Loader2,
  Minus,
  Receipt,
  RefreshCw,
  Repeat,
  TrendingUp,
  UserRound,
  UserX,
  X,
  XCircle,
  type LucideIcon,
} from "lucide-react";
import { TAXA_DA_PLATAFORMA, type ChanceGlobal, type ChanceGlobalAberta, type ChaveDoFator, type FatorDaChance } from "@/lib/chance-global";
import { porcentoLegivel } from "@/lib/metricas-do-link";
import { AnelDeValor } from "../metricas-do-link/graficos";
import { faixaDaChance, quandoFoi } from "../metricas-do-link/janela";

/*
  A janela "Chance de fechar" do orçamento: a chance no geral (a da faixa),
  o que pesa neste orçamento, em pontos, e como a conta foi feita e testada.
  A conta mora em lib/chance-global.ts; a chance pelo link continua na
  janela de métricas do link.
*/

const semAssinatura = () => () => {};

export function useChanceDeFechar(quoteId: string | null, versao: string) {
  const [chance, setChance] = useState<ChanceGlobal | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const [carregando, setCarregando] = useState(false);
  const vez = useRef(0);

  const recarregar = useCallback(async () => {
    if (!quoteId) return;
    const minha = ++vez.current;
    setCarregando(true);
    try {
      const resposta = await fetch(`/api/quotes/${quoteId}/chance-de-fechar`, { cache: "no-store" });
      const dados = (await resposta.json().catch(() => null)) as (ChanceGlobal & { error?: string }) | null;
      if (minha !== vez.current) return;
      if (!resposta.ok || !dados || !("estado" in dados)) {
        setErro(dados?.error || "Não deu para calcular a chance agora.");
        return;
      }
      setChance(dados);
      setErro(null);
    } catch {
      if (minha === vez.current) setErro("Sem conexão com o servidor. Tente de novo em instantes.");
    } finally {
      if (minha === vez.current) setCarregando(false);
    }
  }, [quoteId]);

  /* Recalcula quando o orçamento muda (valor, status, pedido gerado). */
  useEffect(() => {
    if (quoteId) void recarregar();
  }, [quoteId, versao, recarregar]);

  return { chance, erro, carregando, recarregar };
}

const ICONE_DO_FATOR: Record<ChaveDoFator, LucideIcon> = {
  empresa: Building2,
  tempo: Clock3,
  cliente: UserRound,
  "fechou-antes": BadgeCheck,
  "mais-novo": Repeat,
  ticket: Receipt,
  valor: Receipt,
  generico: UserX,
};

function Eyebrow({ children }: { children: ReactNode }) {
  return <p className="text-[10.5px] font-bold uppercase tracking-[0.14em] text-[var(--ks-color-text-soft)]">{children}</p>;
}

/* Quanto o fator mexe: pílula com os pontos e uma barrinha que cresce do
   meio (para cima, verde; para baixo, vermelha). 40 pontos enchem a barra. */
function Efeito({ efeito }: { efeito: number | null }) {
  if (efeito === null) {
    return <span className="text-[11.5px] font-semibold text-[var(--ks-color-text-soft)]">sem peso</span>;
  }
  const pontos = Math.round(efeito * 100);
  const tom = pontos > 0 ? "var(--ks-color-status-success)" : pontos < 0 ? "var(--ks-color-status-danger)" : "var(--ks-color-text-soft)";
  const largura = Math.min(50, (Math.abs(efeito) / 0.4) * 50);
  return (
    <span className="flex shrink-0 flex-col items-end gap-1.5">
      <span className="text-[12.5px] font-extrabold tabular-nums" style={{ color: tom }}>
        {pontos > 0 ? `+${pontos}` : pontos < 0 ? `−${Math.abs(pontos)}` : "0"} pts
      </span>
      <span aria-hidden className="relative h-1.5 w-16 overflow-hidden rounded-full bg-[var(--ks-color-bg-soft)]">
        <span className="absolute inset-y-0 left-1/2 w-px bg-[var(--ks-color-border-strong)]" />
        {pontos !== 0 ? (
          <span
            className="absolute inset-y-0 rounded-full"
            style={{ background: tom, width: `${largura}%`, left: pontos > 0 ? "50%" : `${50 - largura}%` }}
          />
        ) : null}
      </span>
    </span>
  );
}

function LinhaDoFator({ fator }: { fator: FatorDaChance }) {
  const Icone = ICONE_DO_FATOR[fator.chave];
  return (
    <li className="flex items-start gap-3 border-t border-[var(--ks-color-border-subtle)]/60 py-3 first:border-t-0">
      <Icone size={16} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
      <div className="min-w-0 flex-1">
        <div className="text-sm font-semibold text-[var(--ks-color-text-primary)]">{fator.titulo}</div>
        <div className="mt-0.5 text-[13px] leading-5 text-[var(--ks-color-text-muted)]">{fator.detalhe}</div>
      </div>
      <Efeito efeito={fator.efeito} />
    </li>
  );
}

function PontoNoTempo({ rotulo, chance, atraso }: { rotulo: string; chance: number; atraso: number }) {
  return (
    <div className="flex flex-col items-center gap-1.5">
      <AnelDeValor fracao={chance} tamanho={64} espessura={6} cor={faixaDaChance(chance).cor} atraso={atraso} rotulo={`${rotulo}: ${porcentoLegivel(chance)}`}>
        <span className="text-[13.5px] font-extrabold text-[var(--ks-color-text-primary)]">{porcentoLegivel(chance)}</span>
      </AnelDeValor>
      <span className="text-center text-[11.5px] font-semibold text-[var(--ks-color-text-muted)]">{rotulo}</span>
    </div>
  );
}

const PRECISAO = {
  alta: "precisão alta",
  media: "precisão média",
  baixa: "precisão baixa",
} as const;

function ChanceAberta({ chance }: { chance: ChanceGlobalAberta }) {
  const faixa = faixaDaChance(chance.chance);
  const cadaCem = Math.max(1, Math.round(chance.chance * 100));
  const { empresa } = chance;
  return (
    <div className="space-y-6">
      <section className="flex flex-col items-center gap-5 sm:flex-row sm:gap-7">
        <AnelDeValor fracao={chance.chance} tamanho={140} cor={faixa.cor} rotulo={`Chance de fechar: ${porcentoLegivel(chance.chance)}`}>
          <span className="text-[34px] font-extrabold tracking-tight text-[var(--ks-color-text-primary)]">
            {porcentoLegivel(chance.chance).replace("%", "")}
            <span className="text-[17px]">%</span>
          </span>
          <span className="mt-1 text-[11px] font-semibold text-[var(--ks-color-text-muted)]">de fechar</span>
        </AnelDeValor>
        <div className="min-w-0 flex-1 text-center sm:text-left">
          <div className="mb-1.5 inline-flex items-center gap-1.5 text-sm font-bold text-[var(--ks-color-text-primary)]">
            <faixa.Icone size={16} style={{ color: faixa.cor }} aria-hidden />
            {faixa.rotulo} · {PRECISAO[chance.precisao]}
          </div>
          <p className="text-sm leading-6 text-[var(--ks-color-text-secondary)]">
            Com o jeito da sua empresa e a história deste cliente com vocês, de cada 100 orçamentos assim cerca de{" "}
            <strong className="font-semibold text-[var(--ks-color-text-primary)]">{cadaCem}</strong> viram pedido. Um orçamento típico da
            plataforma, com o mesmo tempo aberto, ficaria em {porcentoLegivel(chance.referencia)}.
          </p>
        </div>
      </section>

      <section>
        <Eyebrow>Se nada mudar</Eyebrow>
        <div className="mt-3 grid grid-cols-3 gap-2 sm:max-w-md">
          <PontoNoTempo rotulo="Amanhã" chance={chance.amanha} atraso={0.1} />
          <PontoNoTempo rotulo="Em 7 dias" chance={chance.emUmaSemana} atraso={0.2} />
          <PontoNoTempo rotulo="Em 30 dias" chance={chance.emUmMes} atraso={0.3} />
        </div>
        <p className="mt-3 text-[12.5px] text-[var(--ks-color-text-muted)]">
          Orçamento sem resposta perde força a cada dia: nos dados, a maior parte dos que fecham fecha na primeira semana.
        </p>
      </section>

      <section>
        <Eyebrow>O que pesa neste orçamento</Eyebrow>
        <ul className="mt-1">
          {chance.fatores.map((fator) => (
            <LinhaDoFator key={fator.chave} fator={fator} />
          ))}
        </ul>
        {chance.semPeso.length ? (
          <div className="mt-2 rounded-2xl bg-[var(--ks-color-bg-inset)] px-4 py-3">
            <p className="text-[12px] font-semibold text-[var(--ks-color-text-secondary)]">Também sabemos, mas ainda não pesa:</p>
            <ul className="mt-1.5 space-y-1">
              {chance.semPeso.map((fato) => (
                <li key={fato.titulo} className="flex items-start gap-2 text-[12.5px] leading-5 text-[var(--ks-color-text-muted)]">
                  <Minus size={12} className="mt-1 shrink-0" aria-hidden />
                  <span>
                    <span className="font-semibold text-[var(--ks-color-text-secondary)]">{fato.titulo}:</span> {fato.detalhe}
                  </span>
                </li>
              ))}
            </ul>
          </div>
        ) : null}
      </section>

      <section>
        <Eyebrow>Como a conta é feita</Eyebrow>
        <ul className="mt-2 space-y-2.5 text-[13px] leading-5 text-[var(--ks-color-text-secondary)]">
          <li className="flex items-start gap-2.5">
            <Building2 size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
            <span>
              <strong className="font-semibold text-[var(--ks-color-text-primary)]">Da sua empresa:</strong>{" "}
              {empresa.orcamentos >= 20
                ? `a taxa de fechamento dos ${empresa.orcamentos.toLocaleString("pt-BR")} orçamentos de vocês no último ano, com mais peso no que aconteceu agora (um orçamento de um mês atrás vale metade de um de hoje). É o que mais pesa.`
                : empresa.orcamentos > 0
                  ? `a taxa de fechamento dos ${empresa.orcamentos} ${empresa.orcamentos === 1 ? "orçamento" : "orçamentos"} de vocês no último ano, completada pela média das empresas (${porcentoLegivel(TAXA_DA_PLATAFORMA)}) enquanto o histórico é pequeno. A precisão sobe com mais orçamentos.`
                  : `ainda sem histórico, a conta usa a média das empresas (${porcentoLegivel(TAXA_DA_PLATAFORMA)}) até os orçamentos de vocês terem desfecho.`}
            </span>
          </li>
          <li className="flex items-start gap-2.5">
            <UserRound size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
            <span>
              <strong className="font-semibold text-[var(--ks-color-text-primary)]">Deste cliente com vocês:</strong> se já comprou, se já aceitou
              orçamento, o ticket médio dele e se existe um orçamento mais novo para ele.
            </span>
          </li>
          <li className="flex items-start gap-2.5">
            <FlaskConical size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
            <span>
              <strong className="font-semibold text-[var(--ks-color-text-primary)]">De todas as empresas:</strong> quanto cada um desses fatos pesa e
              como a chance cai com o tempo, medidos em 2.664 orçamentos reais acompanhados até virarem pedido ou não. Vendas do PDV e pedidos lançados na
              hora não entram: não são propostas à espera do cliente.
            </span>
          </li>
          <li className="flex items-start gap-2.5">
            <CheckCircle2 size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
            <span>
              Testada em orçamentos que ela não conhecia, acertou qual fechava mais em 83 de cada 100 comparações (só pelo tempo aberto, 71). Quando diz
              25%, fecham cerca de 25 em cada 100.
            </span>
          </li>
          <li className="flex items-start gap-2.5">
            <Repeat size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
            <span>
              Também testamos, e ficaram de fora porque erraram mais nos meses seguintes: medir os pesos só com os orçamentos de cada empresa (o jeito de
              cada uma muda de um mês para o outro), recorrência, número de compras e dias desde a última compra. Serão medidos de novo com mais tempo de
              dados.
            </span>
          </li>
        </ul>
      </section>

      <p className="flex items-start gap-2.5 rounded-2xl bg-[var(--ks-color-bg-inset)] px-4 py-3 text-[12.5px] leading-5 text-[var(--ks-color-text-secondary)]">
        <TrendingUp size={15} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" aria-hidden />
        <span>O que o cliente faz no link (aberturas, tempo de leitura, aparelhos) fica nas métricas do link, com a chance pelo link.</span>
      </p>
    </div>
  );
}

function ChanceEncerrada({ chance }: { chance: Exclude<ChanceGlobal, ChanceGlobalAberta> }) {
  const { Icone, cor, titulo, texto }: { Icone: LucideIcon; cor: string; titulo: string; texto: string } =
    chance.estado === "fechado"
      ? {
          Icone: CheckCircle2,
          cor: "var(--ks-color-status-success)",
          titulo: "Virou pedido",
          texto: chance.em ? `Este orçamento virou pedido em ${quandoFoi(chance.em)}.` : "Este orçamento já virou pedido.",
        }
      : chance.estado === "aprovado"
        ? {
            Icone: BadgeCheck,
            cor: "var(--ks-color-status-warning)",
            titulo: "Aprovado, sem pedido",
            texto:
              "O orçamento está marcado como aprovado no painel, mas o pedido ainda não foi gerado. Ele só vira pedido quando você clica em Gerar pedido ou quando o cliente aprova pelo link.",
          }
      : chance.estado === "recusado"
        ? { Icone: XCircle, cor: "var(--ks-color-status-danger)", titulo: "Recusado", texto: "Este orçamento foi recusado." }
        : { Icone: Minus, cor: "var(--ks-color-text-soft)", titulo: "Sem conta de chance", texto: chance.motivo };
  return (
    <div className="flex flex-col items-center gap-4 py-4 text-center sm:flex-row sm:text-left">
      <AnelDeValor fracao={chance.estado === "fechado" || chance.estado === "aprovado" ? 1 : 0} tamanho={120} cor={cor} rotulo={titulo}>
        <Icone size={26} style={{ color: cor }} />
      </AnelDeValor>
      <div className="max-w-md">
        <p className="text-base font-bold text-[var(--ks-color-text-primary)]">{titulo}</p>
        <p className="mt-1 text-sm text-[var(--ks-color-text-secondary)]">{texto}</p>
      </div>
    </div>
  );
}

export function JanelaDaChance({
  aberta,
  aoFechar,
  numero,
  cliente,
  chance,
  erro,
  carregando,
  aoRecarregar,
}: {
  aberta: boolean;
  aoFechar: () => void;
  numero: number | null;
  cliente: string | null;
  chance: ChanceGlobal | null;
  erro: string | null;
  carregando: boolean;
  aoRecarregar: () => Promise<void> | void;
}) {
  const parado = useReducedMotion();
  /* A janela vai para o body: no servidor não há body, então só desenha no navegador. */
  const montado = useSyncExternalStore(semAssinatura, () => true, () => false);
  const painel = useRef<HTMLDivElement | null>(null);
  const antes = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (!aberta) return;
    antes.current = document.activeElement as HTMLElement | null;
    const rolagem = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const aoTeclar = (evento: KeyboardEvent) => {
      if (evento.key === "Escape") {
        evento.stopPropagation();
        aoFechar();
      }
    };
    window.addEventListener("keydown", aoTeclar);
    window.setTimeout(() => painel.current?.focus(), 30);
    return () => {
      document.body.style.overflow = rolagem;
      window.removeEventListener("keydown", aoTeclar);
      antes.current?.focus?.();
    };
  }, [aberta, aoFechar]);

  if (!montado) return null;

  return createPortal(
    <AnimatePresence>
      {aberta ? (
        <motion.div
          key="fundo"
          className="fixed inset-0 z-[80] flex items-end justify-center bg-[rgba(20,16,48,0.45)] backdrop-blur-[2px] sm:items-center sm:p-6"
          initial={parado ? false : { opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onMouseDown={(evento) => {
            if (evento.target === evento.currentTarget) aoFechar();
          }}
        >
          <motion.div
            ref={painel}
            role="dialog"
            aria-modal="true"
            aria-labelledby="titulo-chance-de-fechar"
            tabIndex={-1}
            className="flex max-h-[92dvh] w-full flex-col overflow-hidden rounded-t-3xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] shadow-[var(--ks-shadow-overlay)] outline-none sm:max-h-[min(88vh,860px)] sm:max-w-[680px] sm:rounded-3xl"
            initial={parado ? false : { y: 24, opacity: 0 }}
            animate={{ y: 0, opacity: 1 }}
            exit={parado ? { opacity: 0 } : { y: 16, opacity: 0 }}
            transition={{ duration: 0.22, ease: [0.22, 1, 0.36, 1] }}
          >
            <div className="flex justify-center pt-2 sm:hidden" aria-hidden>
              <span className="h-1 w-10 rounded-full bg-[var(--ks-color-border-strong)]" />
            </div>

            <header className="flex items-start gap-3 border-b border-[var(--ks-color-border-subtle)] px-5 pb-4 pt-3 sm:px-7 sm:pt-6">
              <span
                aria-hidden
                className="flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl text-white"
                style={{ background: "linear-gradient(135deg, var(--ks-brand-500) 0%, var(--ks-brand-700) 100%)", boxShadow: "var(--ks-shadow-brand)" }}
              >
                <TrendingUp size={19} strokeWidth={2.3} />
              </span>
              <div className="min-w-0 flex-1">
                <h2 id="titulo-chance-de-fechar" className="text-base font-extrabold tracking-tight text-[var(--ks-color-text-primary)] sm:text-lg">
                  Chance de fechar
                </h2>
                <p className="truncate text-[13px] text-[var(--ks-color-text-muted)]">
                  {numero ? `Orçamento #${numero}` : "Orçamento"}
                  {cliente ? ` · ${cliente}` : ""}
                </p>
              </div>
              <div className="flex shrink-0 items-center gap-1.5">
                <button
                  type="button"
                  onClick={() => void aoRecarregar()}
                  disabled={carregando}
                  aria-label="Atualizar"
                  title="Atualizar"
                  className="ks-icon-button ks-icon-button-sm"
                >
                  <RefreshCw size={15} className={carregando ? "animate-spin" : ""} />
                </button>
                <button type="button" onClick={aoFechar} aria-label="Fechar" className="ks-icon-button ks-icon-button-sm">
                  <X size={15} />
                </button>
              </div>
            </header>

            <div className="min-h-0 flex-1 overflow-y-auto px-5 py-5 sm:px-7 sm:py-6">
              {!chance ? (
                erro ? (
                  <div className="flex flex-col items-center gap-3 py-10 text-center">
                    <p className="text-sm text-[var(--ks-color-text-secondary)]">{erro}</p>
                    <button type="button" onClick={() => void aoRecarregar()} className="ks-button ks-button-secondary ks-button-sm">
                      <RefreshCw size={14} />
                      Tentar de novo
                    </button>
                  </div>
                ) : (
                  <div className="flex items-center justify-center gap-2 py-16 text-sm text-[var(--ks-color-text-muted)]">
                    <Loader2 size={16} className="animate-spin" />
                    Calculando a chance…
                  </div>
                )
              ) : (
                <div className={`transition-opacity ${carregando ? "opacity-70" : "opacity-100"}`}>
                  {chance.estado === "aberto" ? <ChanceAberta chance={chance} /> : <ChanceEncerrada chance={chance} />}
                </div>
              )}
            </div>
          </motion.div>
        </motion.div>
      ) : null}
    </AnimatePresence>,
    document.body
  );
}
