"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import Link from "next/link";
import { BadgeCheck, CheckCircle2, FileText, FlaskConical, Loader2, Package, RotateCcw, Store, Wrench, XCircle } from "lucide-react";

import { pedirFiscal } from "@/components/fiscal/comum";
import { Aviso } from "@/components/ui/aviso";
import CaixaDeConfirmacao, { type Confirmacao } from "@/components/ui/caixa-de-confirmacao";
import { CustomSelect } from "@/components/ui/custom-select";
import { Switch } from "@/components/ui/switch";
import { lerPreferencias, type PreferenciasFiscais, type Presenca } from "@/lib/fiscal/emissor";
import type { NotaNaTela } from "@/lib/fiscal/servidor/apresentacao";

import { Bloco, passoFeito, TopoDoPasso } from "./campos";
import type { PropsDoPasso } from "./cliente";

type Modelo = "nfe" | "nfce" | "nfse";

const MODELOS: Record<Modelo, { titulo: string; Icone: typeof Package; quem: string }> = {
  nfe: { titulo: "Nota de produto", Icone: Package, quem: "Secretaria da Fazenda" },
  nfce: { titulo: "Cupom fiscal", Icone: Store, quem: "Secretaria da Fazenda" },
  nfse: { titulo: "Nota de serviço", Icone: Wrench, quem: "prefeitura" },
};

export function PassoTestar({ painel, recarregar, irPara }: PropsDoPasso) {
  const emissor = painel.emissor;
  const [notas, setNotas] = useState<Partial<Record<Modelo, NotaNaTela>>>(() => painel.ultimosTestes ?? {});
  const [enviando, setEnviando] = useState<Modelo | null>(null);
  const [erros, setErros] = useState<Partial<Record<Modelo, string>>>({});
  const [ativando, setAtivando] = useState<Modelo | null>(null);
  const [erroGeral, setErroGeral] = useState<string | null>(null);
  const [confirmacao, setConfirmacao] = useState<Confirmacao | null>(null);
  const [preferencias, setPreferencias] = useState<PreferenciasFiscais>(
    () => emissor?.preferencias ?? lerPreferencias(null)
  );
  const [situacaoDasPreferencias, setSituacaoDasPreferencias] = useState<"parado" | "salvando" | "salvo" | "erro">("parado");
  const primeiraVez = useRef(true);

  const ligados = emissor ? (["nfe", "nfce", "nfse"] as Modelo[]).filter((modelo) => emissor[modelo].ativo) : [];
  const emAndamento = Object.values(notas).some((nota) => nota?.emAndamento);
  const prontoParaValer = passoFeito(painel, "empresa") && passoFeito(painel, "certificado") && passoFeito(painel, "modelos") && passoFeito(painel, "tributacao") && passoFeito(painel, "teste");

  const atualizar = useCallback(async () => {
    const entradas = await Promise.all(
      Object.entries(notas).map(async ([modelo, nota]) => {
        if (!nota || !nota.emAndamento) return [modelo, nota] as const;
        try {
          const json = await pedirFiscal<{ nota: NotaNaTela }>(`/api/fiscal/notas/${nota.id}`);
          return [modelo, json.nota] as const;
        } catch {
          return [modelo, nota] as const;
        }
      })
    );
    setNotas(Object.fromEntries(entradas));
    if (entradas.some(([, nota]) => nota && !nota.emAndamento && nota.status === "autorizada")) void recarregar();
  }, [notas, recarregar]);

  useEffect(() => {
    if (!emAndamento) return;
    const relogio = setInterval(() => void atualizar(), 3000);
    return () => clearInterval(relogio);
  }, [emAndamento, atualizar]);

  /* As preferências salvam sozinhas, um instante depois da última mudança. */
  useEffect(() => {
    if (primeiraVez.current) {
      primeiraVez.current = false;
      return;
    }
    const relogio = setTimeout(async () => {
      setSituacaoDasPreferencias("salvando");
      try {
        await pedirFiscal("/api/fiscal/preferencias", { method: "PUT", json: preferencias });
        setSituacaoDasPreferencias("salvo");
      } catch {
        setSituacaoDasPreferencias("erro");
      }
    }, 600);
    return () => clearTimeout(relogio);
  }, [preferencias]);

  const emitirTeste = async (modelo: Modelo) => {
    setEnviando(modelo);
    setErros((antes) => ({ ...antes, [modelo]: undefined }));
    try {
      const json = await pedirFiscal<{ nota: { id: string } }>("/api/fiscal/teste", { method: "POST", json: { modelo } });
      const detalhe = await pedirFiscal<{ nota: NotaNaTela }>(`/api/fiscal/notas/${json.nota.id}`);
      setNotas((antes) => ({ ...antes, [modelo]: detalhe.nota }));
    } catch (e) {
      setErros((antes) => ({ ...antes, [modelo]: e instanceof Error ? e.message : "Não foi possível emitir o teste." }));
    } finally {
      setEnviando(null);
    }
  };

  const mudarAmbiente = async (modelo: Modelo, valendo: boolean) => {
    if (!emissor) return;
    setAtivando(modelo);
    setErroGeral(null);
    try {
      const deTeste = modelo === "nfse" ? "simulacao" : "homologacao";
      await pedirFiscal("/api/fiscal/modelos", {
        method: "PUT",
        json: {
          nfe: modelo === "nfe" ? { ...emissor.nfe, ambiente: valendo ? "producao" : "homologacao" } : emissor.nfe,
          nfce: modelo === "nfce" ? { ...emissor.nfce, ambiente: valendo ? "producao" : "homologacao" } : emissor.nfce,
          nfse: modelo === "nfse" ? { ...emissor.nfse, ambiente: valendo ? "producao" : deTeste, cidade: undefined } : { ...emissor.nfse, cidade: undefined },
          segredos: {},
          numeracao: {},
        },
      });
      await recarregar();
    } catch (e) {
      setErroGeral(e instanceof Error ? e.message : "Não foi possível mudar.");
    } finally {
      setAtivando(null);
    }
  };

  if (!ligados.length) {
    return (
      <div className="space-y-8">
        <TopoDoPasso Icone={FlaskConical} cor="azul" titulo="Testar e começar" texto="Uma nota de teste de R$ 1,00 confirma que está tudo certo antes de emitir de verdade." />
        <Aviso
          tom="neutro"
          titulo="Nenhuma nota ligada ainda"
          acao={
            <button type="button" onClick={() => irPara("notas")} className="ks-button ks-button-primary ks-button-sm">
              Escolher as notas
            </button>
          }
        >
          Ligue pelo menos um tipo de nota no passo 3.
        </Aviso>
      </div>
    );
  }

  return (
    <div className="space-y-8">
      <TopoDoPasso
        Icone={FlaskConical}
        cor="azul"
        titulo="Testar e começar"
        texto="A nota de teste vai de verdade até a Secretaria da Fazenda ou a prefeitura, em modo de teste. Custa R$ 1,00 de mentira: não tem valor fiscal e não gasta o seu pacote."
      />

      <Bloco titulo="1. Emita uma nota de teste">
        <div className="grid grid-cols-1 gap-4 2xl:grid-cols-3">
          {ligados.map((modelo) => {
            const { titulo, Icone, quem } = MODELOS[modelo];
            const nota = notas[modelo];
            const erro = erros[modelo];
            const valendo = emissor?.[modelo].ambiente === "producao";
            const aprovada = nota?.status === "autorizada";
            const recusada = nota && ["rejeitada", "erro", "denegada"].includes(nota.status);
            /* Teste cancelado ou descartado: a pessoa precisa ver que aconteceu, senão o
               cartão fica mudo e parece que nunca houve teste. */
            const encerrada = nota && ["cancelada", "removida"].includes(nota.status);
            return (
              <div key={modelo} className="flex flex-col gap-4 rounded-3xl bg-[var(--ks-color-bg-inset)] p-5">
                <div className="flex items-center gap-4">
                  <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-[var(--ks-color-bg-elevated)] text-[var(--ks-color-primary)] shadow-sm">
                    <Icone size={22} />
                  </span>
                  <div className="min-w-0 flex-1">
                    <p className="text-base font-extrabold text-[var(--ks-color-text-primary)]">{titulo}</p>
                    <p className="text-[13px] text-[var(--ks-color-text-muted)]">{valendo ? "Já está emitindo de verdade." : "Teste de R$ 1,00, sem valor fiscal."}</p>
                  </div>
                </div>

                {nota?.emAndamento || enviando === modelo ? (
                  <p className="flex items-center gap-2 rounded-2xl bg-[var(--ks-color-bg-elevated)] px-4 py-3 text-sm font-semibold text-[var(--ks-color-text-primary)]">
                    <Loader2 size={16} className="animate-spin text-[var(--ks-color-primary)]" />
                    Esperando a resposta da {quem}…
                  </p>
                ) : erro ? (
                  /* A tentativa de agora vem antes do teste antigo: se ela nem saiu (falta um
                     dado, por exemplo), mostrar a recusa de antes faz parecer o mesmo erro. */
                  <div className="rounded-2xl bg-rose-500/10 px-4 py-3 text-sm text-rose-900">
                    <p className="flex items-center gap-2 font-semibold">
                      <XCircle size={16} />
                      Não deu para testar
                    </p>
                    <p className="mt-1">{erro}</p>
                  </div>
                ) : aprovada ? (
                  <p className="flex items-center gap-2 rounded-2xl bg-emerald-500/10 px-4 py-3 text-sm font-semibold text-emerald-800">
                    <CheckCircle2 size={16} />
                    Aprovada pela {quem}. Está tudo certo.
                  </p>
                ) : recusada ? (
                  <div className="rounded-2xl bg-rose-500/10 px-4 py-3 text-sm text-rose-900">
                    <p className="flex items-center gap-2 font-semibold">
                      <XCircle size={16} />
                      {nota?.explicacao?.titulo ?? "O teste foi recusado"}
                    </p>
                    {nota?.explicacao?.dica ? <p className="mt-1">{nota.explicacao.dica}</p> : null}
                    {nota?.mensagem ? (
                      <details className="mt-2">
                        <summary className="cursor-pointer text-xs font-semibold text-rose-800/80">Ver a mensagem original</summary>
                        <p className="mt-1 break-words text-xs text-rose-800/80">{nota.mensagem}</p>
                      </details>
                    ) : null}
                  </div>
                ) : encerrada ? (
                  <p className="flex items-center gap-2 rounded-2xl bg-[var(--ks-color-bg-elevated)] px-4 py-3 text-sm text-[var(--ks-color-text-muted)]">
                    <CheckCircle2 size={16} className="text-[var(--ks-color-text-soft)]" />
                    O último teste foi {nota?.status === "cancelada" ? "cancelado" : "descartado"}. Teste de novo quando quiser.
                  </p>
                ) : null}

                <div className="mt-auto flex flex-wrap gap-2">
                  <button
                    type="button"
                    onClick={() => void emitirTeste(modelo)}
                    disabled={enviando !== null || valendo || Boolean(nota?.emAndamento)}
                    className={`ks-button ${nota || erro ? "ks-button-soft" : "ks-button-primary"}`}
                  >
                    {enviando === modelo ? <Loader2 size={16} className="animate-spin" /> : nota || erro ? <RotateCcw size={16} /> : <FlaskConical size={16} />}
                    {nota || erro ? "Testar de novo" : "Emitir nota de teste"}
                  </button>
                  {nota?.temArquivos ? (
                    <button
                      type="button"
                      onClick={() => window.open(`/api/fiscal/notas/${nota.id}/arquivo?tipo=pdf`, "_blank", "noopener,noreferrer")}
                      className="ks-button ks-button-ghost"
                    >
                      <FileText size={16} />
                      Ver a nota
                    </button>
                  ) : null}
                </div>
              </div>
            );
          })}
        </div>
      </Bloco>

      <Bloco
        titulo="2. Comece a emitir de verdade"
        texto={painel.ambiente === "sandbox" ? undefined : "Ligue cada tipo de nota depois do teste aprovado. A partir daí as notas têm valor fiscal e cada nota autorizada gasta uma do pacote do mês."}
      >
        {erroGeral ? (
          <Aviso tom="ruim" aoFechar={() => setErroGeral(null)}>
            {erroGeral}
          </Aviso>
        ) : null}
        {painel.ambiente === "sandbox" ? (
          <Aviso tom="neutro" titulo="Ambiente de testes do Ktalogu">
            Aqui as notas ficam sempre em modo de teste. Com os testes aprovados, a emissão de verdade é ligada no Ktalogu oficial.
          </Aviso>
        ) : (
          <div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
            {ligados.map((modelo) => {
              const { titulo, Icone } = MODELOS[modelo];
              const valendo = emissor?.[modelo].ambiente === "producao";
              return (
                <div key={modelo} className={`flex items-center gap-4 rounded-3xl p-5 ${valendo ? "bg-emerald-500/10" : "bg-[var(--ks-color-bg-inset)]"}`}>
                  <span className={`flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl ${valendo ? "bg-gradient-to-br from-emerald-400 to-emerald-600 text-white" : "bg-[var(--ks-color-bg-elevated)] text-[var(--ks-color-text-soft)]"}`}>
                    {valendo ? <BadgeCheck size={22} /> : <Icone size={22} />}
                  </span>
                  <div className="min-w-0 flex-1">
                    <p className="text-base font-extrabold text-[var(--ks-color-text-primary)]">{titulo}</p>
                    <p className="text-[13px] text-[var(--ks-color-text-muted)]">{valendo ? "Emitindo de verdade." : "Em modo de teste."}</p>
                  </div>
                  {ativando === modelo ? <Loader2 size={18} className="animate-spin text-[var(--ks-color-primary)]" /> : null}
                  <Switch
                    checked={valendo}
                    disabled={ativando !== null || (!valendo && !prontoParaValer)}
                    onCheckedChange={(ligar) =>
                      setConfirmacao({
                        titulo: ligar ? `Emitir ${titulo.toLowerCase()} de verdade?` : `Voltar ${titulo.toLowerCase()} para o modo de teste?`,
                        texto: ligar
                          ? "A partir de agora as notas deste tipo têm valor fiscal e cada nota autorizada gasta uma nota do pacote do mês."
                          : "As próximas notas deste tipo saem sem valor fiscal, até ligar de novo.",
                        confirmar: ligar ? "Começar a emitir" : "Voltar para teste",
                        tom: ligar ? "normal" : "perigo",
                        aoConfirmar: async () => {
                          setConfirmacao(null);
                          await mudarAmbiente(modelo, ligar);
                        },
                      })
                    }
                  />
                </div>
              );
            })}
          </div>
        )}
        {painel.ambiente !== "sandbox" && !prontoParaValer ? (
          <p className="text-sm text-[var(--ks-color-text-muted)]">A chave libera depois que os passos anteriores estiverem prontos e um teste for aprovado.</p>
        ) : null}
        {painel.ambiente !== "sandbox" ? (
          <p className="text-sm text-[var(--ks-color-text-muted)]">
            As notas de verdade usam o pacote do mês.{" "}
            <Link href="/dashboard/assinatura#notas" className="font-semibold text-[var(--ks-color-primary)] hover:underline">
              Ver pacotes de notas
            </Link>
          </p>
        ) : null}
      </Bloco>

      <Bloco
        titulo="3. No dia a dia"
        texto="Como as notas saem no uso normal. Tudo é salvo sozinho."
        acao={
          situacaoDasPreferencias === "salvando" ? (
            <span className="flex items-center gap-2 text-sm text-[var(--ks-color-text-muted)]">
              <Loader2 size={14} className="animate-spin" /> Salvando…
            </span>
          ) : situacaoDasPreferencias === "salvo" ? (
            <span className="flex items-center gap-2 text-sm font-semibold text-emerald-700">
              <CheckCircle2 size={15} /> Salvo
            </span>
          ) : situacaoDasPreferencias === "erro" ? (
            <span className="text-sm font-semibold text-rose-600">Não foi possível salvar. Tente mudar de novo.</span>
          ) : null
        }
      >
        <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
          <Preferencia titulo="Cupom fiscal no PDV" texto="O que acontece em cada venda do balcão.">
            <div className="w-full sm:w-64">
              <CustomSelect
                options={[
                  { value: "perguntar", label: "Perguntar em cada venda" },
                  { value: "sempre", label: "Emitir em toda venda" },
                  { value: "nunca", label: "Não emitir pelo PDV" },
                ]}
                value={preferencias.nfceNoPdv}
                onChange={(v) => setPreferencias({ ...preferencias, nfceNoPdv: v as PreferenciasFiscais["nfceNoPdv"] })}
              />
            </div>
          </Preferencia>
          <Preferencia titulo="Como costumam ser as vendas dos pedidos" texto="Vai na nota. Dá para trocar em cada nota.">
            <div className="w-full sm:w-64">
              <CustomSelect
                options={[
                  { value: "presence", label: "No balcão, com o cliente" },
                  { value: "telephone", label: "Por telefone ou WhatsApp" },
                  { value: "internet", label: "Pela internet" },
                  { value: "delivery", label: "Com entrega" },
                  { value: "othersNonPresenceOperation", label: "Outra, sem o cliente presente" },
                ]}
                value={preferencias.presencaPedido}
                onChange={(v) => setPreferencias({ ...preferencias, presencaPedido: v as Presenca })}
              />
            </div>
          </Preferencia>
          <Preferencia titulo="Mandar a nota por e-mail ao cliente" texto="O PDF e o arquivo da nota vão para o e-mail do cadastro do cliente.">
            <Switch checked={preferencias.enviarEmail} onCheckedChange={(v) => setPreferencias({ ...preferencias, enviarEmail: v })} />
          </Preferencia>
          <Preferencia titulo="Emitir sozinha nas vendas pagas da loja virtual" texto="Quando o pagamento online é aprovado, a nota de produto sai sem ninguém clicar.">
            <Switch checked={preferencias.emitirNaLoja} onCheckedChange={(v) => setPreferencias({ ...preferencias, emitirNaLoja: v })} />
          </Preferencia>
          <Preferencia titulo="Meus clientes usam o que compram" texto="O caso comum. Desligue só se a maioria dos clientes revende o que compra de você.">
            <Switch checked={preferencias.consumidorFinal} onCheckedChange={(v) => setPreferencias({ ...preferencias, consumidorFinal: v })} />
          </Preferencia>
        </div>
      </Bloco>

      {passoFeito(painel, "teste") ? (
        <div className="flex flex-col gap-4 rounded-3xl bg-gradient-to-br from-violet-500 to-purple-600 p-6 text-white shadow-[0_18px_40px_rgba(124,58,237,0.3)] sm:flex-row sm:items-center">
          <CheckCircle2 size={36} className="shrink-0" />
          <div className="min-w-0 flex-1">
            <p className="text-lg font-extrabold">Tudo pronto para emitir</p>
            <p className="text-sm text-white/85">Abra um pedido e clique em Emitir nota, ou ligue o cupom fiscal no PDV.</p>
          </div>
          <Link href="/dashboard/orders" className="inline-flex h-11 items-center rounded-xl bg-white px-5 text-sm font-bold text-[var(--ks-color-primary)] transition hover:bg-white/90">
            Ir para Pedidos
          </Link>
        </div>
      ) : null}

      <CaixaDeConfirmacao pedido={confirmacao} ocupado={ativando !== null} aoFechar={() => setConfirmacao(null)} />
    </div>
  );
}

function Preferencia({ titulo, texto, children }: { titulo: string; texto: string; children: React.ReactNode }) {
  return (
    <div className="flex flex-col gap-3 rounded-2xl bg-[var(--ks-color-bg-inset)] px-5 py-4 sm:flex-row sm:items-center sm:justify-between">
      <div className="min-w-0">
        <p className="text-sm font-bold text-[var(--ks-color-text-primary)]">{titulo}</p>
        <p className="text-[13px] leading-5 text-[var(--ks-color-text-muted)]">{texto}</p>
      </div>
      <div className="shrink-0">{children}</div>
    </div>
  );
}
