"use client";

import { useState, type ReactNode } from "react";
import { Check, ChevronDown, Loader2 } from "lucide-react";

import { Dica } from "@/components/fiscal/dica";
import type { ChaveDeLinkOficial } from "@/lib/fiscal/tabelas";

export type EmissorNaTela = import("@/lib/fiscal/servidor/emissor").EmissorNaTela;

export type Passo = {
  chave: "empresa" | "certificado" | "modelos" | "tributacao" | "produtos" | "teste" | "producao";
  feito: boolean;
  detalhe: string | null;
};

export type PerfilNaTela = {
  id: string;
  nome: string;
  tipo: "mercadoria" | "servico";
  padrao: boolean;
  ativo: boolean;
  regras: Record<string, unknown>;
};

export type PainelNaTela = {
  ambiente: "sandbox" | "producao";
  servidorPronto: boolean;
  emissor: EmissorNaTela | null;
  /** O resultado do último teste de cada tipo de nota, para não sumir ao recarregar. */
  ultimosTestes?: Partial<Record<"nfe" | "nfce" | "nfse", import("@/lib/fiscal/servidor/apresentacao").NotaNaTela>>;
  passos: Passo[];
  perfis: PerfilNaTela[];
  produtosSemNcm: number;
  sugestaoDaLoja: {
    razaoSocial: string;
    cnpj: string;
    email: string;
    telefone: string;
    endereco: { cep: string; logradouro: string; numero: string; complemento: string; bairro: string; cidade: string; uf: string };
  };
};

export function passoFeito(painel: PainelNaTela, chave: Passo["chave"]) {
  return painel.passos.find((p) => p.chave === chave)?.feito ?? false;
}

/* ------------------------------------------------------------------ */
/* Campos                                                              */
/* ------------------------------------------------------------------ */

export function Campo({
  rotulo,
  dica,
  erro,
  children,
  className = "",
  opcional = false,
  ajuda,
  link,
}: {
  rotulo: string;
  dica?: ReactNode;
  erro?: string | null;
  children: ReactNode;
  className?: string;
  opcional?: boolean;
  /** O que a sigla quer dizer, em uma frase. Vira a bolinha de interrogação. */
  ajuda?: ReactNode;
  /** O site oficial onde esse número é conseguido, quando existe um. */
  link?: ChaveDeLinkOficial;
}) {
  return (
    <label className={`block space-y-2 ${className}`}>
      <span className="flex items-baseline gap-2 text-sm font-semibold text-[var(--ks-color-text-primary)]">
        <span className="inline-flex items-baseline">
          {rotulo}
          {ajuda || link ? (
            <Dica titulo={rotulo} link={link}>
              {ajuda}
            </Dica>
          ) : null}
        </span>
        {opcional ? <span className="text-xs font-normal text-[var(--ks-color-text-soft)]">opcional</span> : null}
      </span>
      {children}
      {erro ? (
        <span className="block text-xs font-semibold text-rose-600">{erro}</span>
      ) : dica ? (
        <span className="block text-xs leading-5 text-[var(--ks-color-text-muted)]">{dica}</span>
      ) : null}
    </label>
  );
}

export function Escolha<T extends string>({
  opcoes,
  valor,
  aoMudar,
  colunas = 2,
}: {
  opcoes: Array<{ valor: T; titulo: string; texto?: string; selo?: string; desligado?: boolean }>;
  valor: T | "" | null;
  aoMudar: (valor: T) => void;
  colunas?: 1 | 2 | 3 | 4;
}) {
  const grade = { 1: "", 2: "md:grid-cols-2", 3: "md:grid-cols-3", 4: "md:grid-cols-2 2xl:grid-cols-4" }[colunas];
  return (
    <div className={`grid grid-cols-1 gap-3 ${grade}`}>
      {opcoes.map((opcao) => {
        const ativa = valor === opcao.valor;
        return (
          <button
            key={opcao.valor}
            type="button"
            disabled={opcao.desligado}
            onClick={() => aoMudar(opcao.valor)}
            aria-pressed={ativa}
            className={`relative rounded-2xl px-5 py-4 text-left transition disabled:cursor-not-allowed disabled:opacity-40 ${
              ativa
                ? "bg-gradient-to-br from-violet-500 to-purple-600 text-white shadow-[0_12px_28px_rgba(124,58,237,0.30)]"
                : "bg-[var(--ks-color-bg-inset)] text-[var(--ks-color-text-primary)] hover:bg-[var(--ks-color-bg-hover)]"
            }`}
          >
            <span className="flex items-center gap-2 pr-6 text-[15px] font-bold">
              {opcao.titulo}
              {opcao.selo ? (
                <span
                  className={`rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-[0.08em] ${
                    ativa ? "bg-white/20 text-white" : "bg-emerald-500/10 text-emerald-700"
                  }`}
                >
                  {opcao.selo}
                </span>
              ) : null}
            </span>
            {opcao.texto ? <span className={`mt-1 block text-[13px] leading-5 ${ativa ? "text-white/85" : "text-[var(--ks-color-text-muted)]"}`}>{opcao.texto}</span> : null}
            {ativa ? (
              <span className="absolute right-4 top-4 flex h-6 w-6 items-center justify-center rounded-full bg-white/25">
                <Check size={14} strokeWidth={3} />
              </span>
            ) : null}
          </button>
        );
      })}
    </div>
  );
}

/** Um bloco do passo: título forte, texto de apoio e o conteúdo. */
export function Bloco({ titulo, texto, children, acao }: { titulo: string; texto?: ReactNode; children: ReactNode; acao?: ReactNode }) {
  return (
    <section className="space-y-5 border-t border-[var(--ks-color-border-subtle)] pt-8 first:border-t-0 first:pt-0">
      <div className="flex flex-wrap items-start justify-between gap-3">
        <div className="max-w-3xl">
          <h3 className="text-lg font-extrabold tracking-tight text-[var(--ks-color-text-primary)]">{titulo}</h3>
          {texto ? <p className="mt-1 text-sm leading-6 text-[var(--ks-color-text-muted)]">{texto}</p> : null}
        </div>
        {acao}
      </div>
      {children}
    </section>
  );
}

/** O cabeçalho do passo. */
export function TopoDoPasso({ Icone, titulo, texto, cor = "violeta" }: { Icone: typeof Check; titulo: string; texto: ReactNode; cor?: "violeta" | "verde" | "azul" }) {
  const fundo =
    cor === "verde"
      ? "from-emerald-400 to-emerald-600 shadow-[0_12px_26px_rgba(16,185,129,0.3)]"
      : cor === "azul"
        ? "from-sky-500 to-indigo-600 shadow-[0_12px_26px_rgba(14,116,244,0.3)]"
        : "from-violet-500 to-purple-600 shadow-[0_12px_26px_rgba(124,58,237,0.3)]";
  return (
    <header className="flex items-start gap-4">
      <span className={`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br text-white ${fundo}`}>
        <Icone size={26} />
      </span>
      <div className="min-w-0">
        <h2 className="text-2xl font-extrabold tracking-tight text-[var(--ks-color-text-primary)]">{titulo}</h2>
        <p className="mt-1 max-w-3xl text-[15px] leading-6 text-[var(--ks-color-text-muted)]">{texto}</p>
      </div>
    </header>
  );
}

/** "Mais opções": o que quase ninguém precisa mexer fica fechado. */
export function Recolhivel({ titulo, children, abertoDeInicio = false }: { titulo: string; children: ReactNode; abertoDeInicio?: boolean }) {
  const [aberto, setAberto] = useState(abertoDeInicio);
  return (
    <div>
      <button
        type="button"
        onClick={() => setAberto((v) => !v)}
        aria-expanded={aberto}
        className="flex items-center gap-1.5 text-sm font-semibold text-[var(--ks-color-primary)] hover:opacity-80"
      >
        <ChevronDown size={16} className={`transition-transform ${aberto ? "rotate-180" : ""}`} />
        {titulo}
      </button>
      {aberto ? <div className="mt-4">{children}</div> : null}
    </div>
  );
}

/** A barra de salvar, presa ao pé da tela enquanto houver o que salvar. */
export function BarraDeSalvar({
  rotulo,
  aoSalvar,
  salvando,
  desabilitado = false,
  mensagem,
  secundario,
  fixa = true,
}: {
  rotulo: string;
  aoSalvar: () => void;
  salvando: boolean;
  desabilitado?: boolean;
  mensagem?: ReactNode;
  secundario?: ReactNode;
  /** Gruda no pé da tela; sem nada para salvar ela fica no fim do passo, sem cobrir o conteúdo. */
  fixa?: boolean;
}) {
  return (
    <div
      className={`flex flex-col gap-3 rounded-2xl px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:px-5 ${
        fixa
          ? "sticky bottom-3 z-20 bg-[var(--ks-color-bg-elevated)] shadow-[0_16px_44px_rgba(26,26,43,0.16)] ring-1 ring-[var(--ks-color-border-subtle)]"
          : "bg-[var(--ks-color-bg-inset)]"
      }`}
    >
      <div className="min-w-0 text-sm text-[var(--ks-color-text-muted)]">{mensagem}</div>
      <div className="flex flex-wrap items-center justify-end gap-2">
        {secundario}
        <button type="button" onClick={aoSalvar} disabled={salvando || desabilitado} className="ks-button ks-button-primary">
          {salvando ? <Loader2 size={16} className="animate-spin" /> : null}
          {rotulo}
        </button>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Máscaras                                                            */
/* ------------------------------------------------------------------ */

export const soDigitos = (valor: string | null | undefined) => String(valor || "").replace(/\D/g, "");

export function mascaraCnpj(valor: string) {
  const d = soDigitos(valor).slice(0, 14);
  return d
    .replace(/^(\d{2})(\d)/, "$1.$2")
    .replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3")
    .replace(/\.(\d{3})(\d)/, ".$1/$2")
    .replace(/(\d{4})(\d)/, "$1-$2");
}

export function mascaraCep(valor: string) {
  const d = soDigitos(valor).slice(0, 8);
  return d.length > 5 ? `${d.slice(0, 5)}-${d.slice(5)}` : d;
}

export function mascaraTelefone(valor: string) {
  const d = soDigitos(valor).slice(0, 11);
  if (d.length <= 2) return d;
  if (d.length <= 6) return `(${d.slice(0, 2)}) ${d.slice(2)}`;
  if (d.length <= 10) return `(${d.slice(0, 2)}) ${d.slice(2, 6)}-${d.slice(6)}`;
  return `(${d.slice(0, 2)}) ${d.slice(2, 7)}-${d.slice(7)}`;
}
