"use client";

import { useCallback } from "react";
import { CopyPlus, PackageSearch, Plus, Trash2 } from "lucide-react";

import { moeda, pedirFiscal } from "@/components/fiscal/comum";
import { Dica } from "@/components/fiscal/dica";
import { CampoDecimal } from "@/components/ui/campo-decimal";
import { CustomSelect } from "@/components/ui/custom-select";
import { iconeDoProduto } from "@/lib/icone-do-item";
import type { Pendencia } from "@/lib/fiscal/montar";
import type { ChaveDeLinkOficial } from "@/lib/fiscal/tabelas";

import { CaixaDeBusca } from "./caixa-de-busca";
import { CampoDeDinheiro } from "./campo-de-dinheiro";
import { CampoNcm } from "./campo-ncm";
import { LIMITE_DE_ITENS, ncmFormatado, novaChave, novaLinha, totalDaLinha, UNIDADES, type Linha, type Modelo, type ProdutoDaEmissao } from "./tipos";

const CORES = ["from-violet-500 to-purple-600", "from-fuchsia-500 to-pink-600", "from-sky-500 to-indigo-600", "from-emerald-400 to-emerald-600"];

function Figura({ nome, foto }: { nome: string; foto: string | null }) {
  const icone = nome.trim() ? iconeDoProduto(nome) : null;
  if (foto) {
    // eslint-disable-next-line @next/next/no-img-element
    return <img src={foto} alt="" className="h-10 w-10 shrink-0 rounded-xl object-cover" />;
  }
  if (icone) {
    // eslint-disable-next-line @next/next/no-img-element
    return <img src={icone} alt="" className="h-10 w-10 shrink-0 object-contain" />;
  }
  const letra = nome.trim().charAt(0).toUpperCase() || "+";
  const cor = CORES[(nome.trim().charCodeAt(0) || 0) % CORES.length];
  return (
    <span className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br text-sm font-bold text-white shadow-sm ${cor}`}>{letra}</span>
  );
}

/** Rótulo do campo: some quando a linha cabe inteira e o cabeçalho da tabela aparece. */
function Rotulo({
  children,
  htmlFor,
  ajuda,
  link,
}: {
  children: string;
  htmlFor?: string;
  ajuda?: string;
  link?: ChaveDeLinkOficial;
}) {
  return (
    <label htmlFor={htmlFor} className="mb-1 flex items-baseline text-xs font-semibold text-[var(--ks-color-text-secondary)] @5xl:hidden">
      {children}
      {ajuda ? (
        <Dica titulo={children} link={link}>
          {ajuda}
        </Dica>
      ) : null}
    </label>
  );
}

/*
 * A linha do item se arruma pela largura do FORMULÁRIO (container query), não
 * da tela: em 1366 px o resumo ao lado deixa o formulário estreito e a tabela
 * de 7 colunas espremia a descrição até sumir.
 *  - estreito (celular): um campo embaixo do outro, dois por linha;
 *  - médio: descrição e total em cima, NCM, unidade, quantidade e valor embaixo;
 *  - largo: uma linha só, com cabeçalho (a partir de 64rem de formulário, para a
 *    descrição não ficar estreita com os botões de duplicar e tirar).
 */
const GRADE_DE_PRODUTO = [
  "grid-cols-[minmax(0,1fr)_minmax(0,1fr)] [grid-template-areas:'desc_desc'_'ncm_unid'_'qtd_valor'_'total_tirar']",
  "@xl:grid-cols-[minmax(0,1.3fr)_88px_minmax(0,0.9fr)_minmax(0,1.1fr)_68px] @xl:[grid-template-areas:'desc_desc_desc_total_tirar'_'ncm_unid_qtd_valor_valor']",
  "@5xl:grid-cols-[minmax(0,1fr)_140px_96px_104px_136px_110px_68px] @5xl:[grid-template-areas:'desc_ncm_unid_qtd_valor_total_tirar']",
].join(" ");
const COLUNAS_DE_PRODUTO_LARGO = "@5xl:grid-cols-[minmax(0,1fr)_140px_96px_104px_136px_110px_68px]";

const GRADE_DE_SERVICO = [
  "grid-cols-[minmax(0,1fr)_minmax(0,1fr)] [grid-template-areas:'desc_desc'_'qtd_valor'_'total_tirar']",
  "@xl:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(96px,auto)_68px] @xl:[grid-template-areas:'desc_desc_total_tirar'_'qtd_valor_valor_valor']",
  "@5xl:grid-cols-[minmax(0,1fr)_120px_150px_120px_68px] @5xl:[grid-template-areas:'desc_qtd_valor_total_tirar']",
].join(" ");
const COLUNAS_DE_SERVICO_LARGO = "@5xl:grid-cols-[minmax(0,1fr)_120px_150px_120px_68px]";

export function BlocoItens({
  modelo,
  linhas,
  aoMudarLinhas,
  problemasDaLinha,
  travado,
}: {
  modelo: Modelo;
  linhas: Linha[];
  aoMudarLinhas: (atualizar: (linhas: Linha[]) => Linha[]) => void;
  problemasDaLinha: (indice: number) => Pendencia[];
  travado: boolean;
}) {
  const servico = modelo === "nfse";
  const cheio = linhas.length >= LIMITE_DE_ITENS;

  const buscarProdutos = useCallback(
    async (termo: string) =>
      (await pedirFiscal<{ produtos: ProdutoDaEmissao[] }>(`/api/fiscal/avulsa/buscas?tipo=produtos&q=${encodeURIComponent(termo)}`)).produtos,
    []
  );

  const mudar = (id: string, parcial: Partial<Linha>) =>
    aoMudarLinhas((atuais) => atuais.map((linha) => (linha.id === id ? { ...linha, ...parcial } : linha)));

  const adicionarProduto = (produto: ProdutoDaEmissao) =>
    aoMudarLinhas((atuais) =>
      atuais.length >= LIMITE_DE_ITENS
        ? atuais
        : [
            ...atuais,
            novaLinha({
              produtoId: produto.id,
              foto: produto.foto,
              descricao: produto.nome.slice(0, 120),
              ncm: produto.ncm ?? "",
              unidade: produto.unidade,
              quantidade: 1,
              valorUnitario: produto.preco,
            }),
          ]
    );

  const duplicar = (id: string) => {
    /* O id nasce fora do atualizador: em desenvolvimento o React roda o atualizador duas vezes. */
    const idDaCopia = novaChave();
    aoMudarLinhas((atuais) => {
      const posicao = atuais.findIndex((linha) => linha.id === id);
      if (posicao < 0 || atuais.length >= LIMITE_DE_ITENS) return atuais;
      return [...atuais.slice(0, posicao + 1), { ...atuais[posicao], id: idDaCopia }, ...atuais.slice(posicao + 1)];
    });
    setTimeout(() => {
      const campo = document.getElementById(`descricao-${idDaCopia}`) as HTMLInputElement | null;
      if (!campo) return;
      campo.scrollIntoView({ behavior: "smooth", block: "nearest" });
      campo.focus();
      campo.setSelectionRange(campo.value.length, campo.value.length);
    }, 60);
  };

  const adicionarSemCadastro = () => {
    const linha = novaLinha();
    aoMudarLinhas((atuais) => (atuais.length >= LIMITE_DE_ITENS ? atuais : [...atuais, linha]));
    setTimeout(() => document.getElementById(`descricao-${linha.id}`)?.focus(), 60);
  };

  return (
    <div className="@container space-y-4">
      <div className="flex flex-col gap-3 @xl:flex-row">
        <div className="min-w-0 flex-1">
          <CaixaDeBusca<ProdutoDaEmissao>
            placeholder={servico ? "Buscar no catálogo" : "Buscar produto no catálogo"}
            buscar={buscarProdutos}
            desabilitado={travado || cheio}
            titulo={(termo) => (termo ? null : "Do seu catálogo")}
            aoEscolher={adicionarProduto}
            renderizar={(produto) => (
              <>
                <Figura nome={produto.nome} foto={produto.foto} />
                <span className="min-w-0 flex-1">
                  <span className="block truncate text-sm font-semibold text-[var(--ks-color-text-primary)]">{produto.nome}</span>
                  <span className="block truncate text-xs text-[var(--ks-color-text-muted)]">
                    {[
                      produto.sku ? `cód. ${produto.sku}` : null,
                      produto.unidade !== "UN" ? `vendido por ${produto.unidade}` : null,
                      servico ? null : produto.ncm ? `NCM ${ncmFormatado(produto.ncm)}` : "sem NCM",
                      produto.ativo ? null : "fora de linha",
                    ]
                      .filter(Boolean)
                      .join(" · ")}
                  </span>
                </span>
                {produto.preco > 0 ? (
                  <span className="ks-num shrink-0 text-sm font-bold text-[var(--ks-color-text-primary)]">{moeda(produto.preco)}</span>
                ) : null}
              </>
            )}
            vazio={(termo) =>
              termo ? (
                <>
                  Nenhum produto com &ldquo;{termo}&rdquo;. Use <strong>Item sem cadastro</strong> para digitar.
                </>
              ) : (
                "Seu catálogo ainda não tem produtos."
              )
            }
          />
        </div>
        <button type="button" onClick={adicionarSemCadastro} disabled={travado || cheio} className="ks-button ks-button-soft shrink-0" style={{ height: "3rem" }}>
          <Plus size={16} />
          Item sem cadastro
        </button>
      </div>

      {cheio ? <p className="text-xs font-semibold text-[var(--ks-color-text-muted)]">Uma nota aceita até {LIMITE_DE_ITENS} itens.</p> : null}

      {linhas.length === 0 ? (
        <div className="flex items-center gap-4 rounded-2xl bg-[var(--ks-color-bg-inset)] px-5 py-5">
          <span className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-[var(--ks-color-bg-elevated)] text-[var(--ks-color-primary)] shadow-sm">
            <PackageSearch size={20} />
          </span>
          <p className="text-sm leading-6 text-[var(--ks-color-text-muted)]">
            Nenhum item ainda. Busque {servico ? "o serviço" : "o produto"} no catálogo ou use <strong>Item sem cadastro</strong> para digitar.
          </p>
        </div>
      ) : (
        <div>
          {/* Cabeçalho só quando a linha cabe inteira (a largura é a do formulário, não a da tela). */}
          <div className={`hidden gap-x-3 pb-2 text-[11px] font-bold uppercase tracking-[0.12em] text-[var(--ks-color-text-soft)] @5xl:grid ${servico ? COLUNAS_DE_SERVICO_LARGO : COLUNAS_DE_PRODUTO_LARGO}`}>
            <span className="pl-[52px]">{servico ? "Serviço" : "Produto"}</span>
            {servico ? null : (
              <span className="flex items-baseline">
                NCM
                <Dica titulo="NCM" link="ncm">
                  Número de 8 dígitos que diz à Receita o que é o produto. Todo produto que sai em nota precisa dele — procure pelo nome na
                  lupa do campo, como adesivo ou lona.
                </Dica>
              </span>
            )}
            {servico ? null : <span>Unidade</span>}
            <span className="text-right">Quantidade</span>
            <span className="text-right">Valor unitário</span>
            <span className="text-right">Total</span>
            <span />
          </div>
          <ul>
            {linhas.map((linha, indice) => {
              const problemas = problemasDaLinha(indice);
              const faltaNcm = problemas.some((p) => p.codigo.startsWith("produto.ncm"));
              return (
                <li key={linha.id} id={`linha-${indice}`} className="scroll-mt-24 border-t border-slate-100/60 py-3 first:border-t-0">
                  <div className={`grid items-start gap-x-3 gap-y-2 ${servico ? GRADE_DE_SERVICO : GRADE_DE_PRODUTO}`}>
                    <div className="flex min-w-0 items-center gap-3 [grid-area:desc]">
                      <Figura nome={linha.descricao} foto={linha.foto} />
                      <div className="min-w-0 flex-1">
                        <input
                          id={`descricao-${linha.id}`}
                          value={linha.descricao}
                          disabled={travado}
                          maxLength={120}
                          onChange={(e) => mudar(linha.id, { descricao: e.target.value })}
                          placeholder={servico ? "O que foi feito" : "O que foi vendido"}
                          aria-label={`Descrição da linha ${indice + 1}`}
                          aria-invalid={problemas.some((p) => p.codigo.startsWith("avulsa.item.descricao"))}
                          className="ks-field"
                        />
                        {linha.produtoId ? <span className="mt-1 block text-[11px] text-[var(--ks-color-text-soft)]">do catálogo · dá para mudar o texto</span> : null}
                      </div>
                    </div>

                    {servico ? null : (
                      <div className="min-w-0 [grid-area:ncm]">
                        <Rotulo htmlFor={`ncm-${linha.id}`} ajuda="Número de 8 dígitos que diz à Receita o que é o produto. Procure pelo nome na lupa." link="ncm">
                          NCM
                        </Rotulo>
                        <CampoNcm
                          id={`ncm-${linha.id}`}
                          valor={linha.ncm}
                          aoMudar={(ncm) => mudar(linha.id, { ncm })}
                          descricaoDaLinha={linha.descricao}
                          invalido={faltaNcm}
                          desabilitado={travado}
                        />
                      </div>
                    )}

                    {servico ? null : (
                      <div className="min-w-0 [grid-area:unid]">
                        <Rotulo>Unidade</Rotulo>
                        <CustomSelect
                          size="sm"
                          disabled={travado}
                          options={UNIDADES.some((u) => u.value === linha.unidade) ? UNIDADES : [...UNIDADES, { value: linha.unidade, label: linha.unidade, description: "Como estava" }]}
                          value={linha.unidade}
                          onChange={(unidade) => mudar(linha.id, { unidade })}
                        />
                      </div>
                    )}

                    <div className="min-w-0 [grid-area:qtd]">
                      <Rotulo htmlFor={`quantidade-${linha.id}`}>Quantidade</Rotulo>
                      <CampoDecimal
                        id={`quantidade-${linha.id}`}
                        valor={linha.quantidade}
                        aoMudar={(quantidade) => mudar(linha.id, { quantidade })}
                        casas={4}
                        disabled={travado}
                        aria-label={`Quantidade da linha ${indice + 1}`}
                        className="ks-field ks-num text-right"
                      />
                    </div>

                    <div className="min-w-0 [grid-area:valor]">
                      <Rotulo htmlFor={`valor-${linha.id}`}>Valor unitário</Rotulo>
                      <div className="relative">
                        <span className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-xs font-semibold text-[var(--ks-color-text-soft)]">R$</span>
                        <CampoDeDinheiro
                          id={`valor-${linha.id}`}
                          valor={linha.valorUnitario}
                          aoMudar={(valorUnitario) => mudar(linha.id, { valorUnitario })}
                          casas={4}
                          placeholder="0,00"
                          disabled={travado}
                          aria-label={`Valor unitário da linha ${indice + 1}`}
                          className="ks-field ks-num text-right"
                          style={{ paddingLeft: "2.25rem" }}
                        />
                      </div>
                    </div>

                    <div className="flex min-w-0 flex-col items-end [grid-area:total]">
                      <span className="mb-1 block text-xs font-semibold text-[var(--ks-color-text-secondary)] @xl:hidden">Total</span>
                      <span className="ks-num flex min-h-[42px] items-center text-[15px] font-bold text-[var(--ks-color-text-primary)]">{moeda(totalDaLinha(linha))}</span>
                    </div>

                    <div className="flex min-h-[42px] items-center justify-end gap-1 self-end [grid-area:tirar] @xl:self-start">
                      <button
                        type="button"
                        disabled={travado || cheio}
                        onClick={() => duplicar(linha.id)}
                        aria-label={`Duplicar a linha ${indice + 1}`}
                        title={cheio ? `Uma nota aceita até ${LIMITE_DE_ITENS} itens` : "Duplicar este item"}
                        className="rounded-xl p-1.5 text-[var(--ks-color-text-soft)] transition hover:bg-violet-500/10 hover:text-[var(--ks-color-primary)] disabled:opacity-40"
                      >
                        <CopyPlus size={17} />
                      </button>
                      <button
                        type="button"
                        disabled={travado}
                        onClick={() => aoMudarLinhas((atuais) => atuais.filter((item) => item.id !== linha.id))}
                        aria-label={`Tirar a linha ${indice + 1}`}
                        title="Tirar este item"
                        className="rounded-xl p-1.5 text-[var(--ks-color-text-soft)] transition hover:bg-rose-500/10 hover:text-rose-600 disabled:opacity-40"
                      >
                        <Trash2 size={17} />
                      </button>
                    </div>
                  </div>
                  {problemas.length ? (
                    <ul className="mt-2 space-y-0.5 @xl:pl-[52px]">
                      {problemas.map((problema) => (
                        <li key={problema.codigo} className="text-xs font-semibold text-rose-600">
                          {problema.titulo.replace(/^Linha \d+: /, "")}
                        </li>
                      ))}
                    </ul>
                  ) : null}
                </li>
              );
            })}
          </ul>
        </div>
      )}
    </div>
  );
}
