"use client";

import { CampoDecimal } from "@/components/ui/campo-decimal";
import { LIMITES, numeroEscrito, type DefinicaoDeCampo } from "@/lib/campos-proprios";

/*
  Os campos próprios dentro de um formulário: um campo por definição ativa,
  com o controle certo para o tipo. Só desenho: quem usa guarda os valores
  (em bruto, como a pessoa digitou) e confere com `conferirValores` ao salvar.
*/

export type ValoresEmEdicao = Record<string, unknown>;

type Props = {
  definicoes: DefinicaoDeCampo[];
  valores: ValoresEmEdicao;
  aoMudar: (chave: string, valor: unknown) => void;
  erros?: Record<string, string>;
  desabilitado?: boolean;
  /** Prefixo dos ids dos campos (dois formulários na mesma tela). */
  prefixo?: string;
  /** Colunas no computador. */
  colunas?: 1 | 2;
};

export function CamposDoFormulario({ definicoes, valores, aoMudar, erros = {}, desabilitado, prefixo = "cp", colunas = 2 }: Props) {
  const ativas = definicoes.filter((def) => def.ativo);
  if (!ativas.length) return null;
  return (
    <div className={`grid grid-cols-1 gap-4 ${colunas === 2 ? "md:grid-cols-2" : ""}`}>
      {ativas.map((def) => {
        const id = `${prefixo}-${def.chave}`;
        const erro = erros[def.chave];
        const largo = def.tipo === "texto_longo" && colunas === 2;
        return (
          <div key={def.id} className={`min-w-0 space-y-1.5 ${largo ? "md:col-span-2" : ""}`}>
            <label htmlFor={id} className="block text-sm font-medium text-[var(--ks-color-text-primary)]">
              {def.rotulo}
              {def.obrigatorio ? <span className="ml-0.5 text-[var(--ks-color-status-danger)]"> *</span> : null}
            </label>
            <ControleDoCampo id={id} def={def} valor={valores[def.chave]} aoMudar={(v) => aoMudar(def.chave, v)} desabilitado={desabilitado} invalido={Boolean(erro)} />
            {erro ? (
              <p className="text-xs font-medium text-[var(--ks-color-status-danger)]">{erro}</p>
            ) : def.ajuda ? (
              <p className="text-xs text-[var(--ks-color-text-soft)]">{def.ajuda}</p>
            ) : null}
          </div>
        );
      })}
    </div>
  );
}

function ControleDoCampo({
  id,
  def,
  valor,
  aoMudar,
  desabilitado,
  invalido,
}: {
  id: string;
  def: DefinicaoDeCampo;
  valor: unknown;
  aoMudar: (valor: unknown) => void;
  desabilitado?: boolean;
  invalido?: boolean;
}) {
  const borda = invalido ? "!border-[var(--ks-color-status-danger)]" : "";
  switch (def.tipo) {
    case "texto":
      return (
        <input
          id={id}
          type="text"
          className={`ks-field ${borda}`}
          value={typeof valor === "string" || typeof valor === "number" ? String(valor) : ""}
          maxLength={LIMITES.texto}
          disabled={desabilitado}
          onChange={(e) => aoMudar(e.target.value)}
        />
      );
    case "texto_longo":
      return (
        <textarea
          id={id}
          className={`ks-field min-h-[76px] resize-y ${borda}`}
          value={typeof valor === "string" || typeof valor === "number" ? String(valor) : ""}
          maxLength={LIMITES.textoLongo}
          disabled={desabilitado}
          onChange={(e) => aoMudar(e.target.value)}
        />
      );
    case "numero":
    case "moeda": {
      const numero = typeof valor === "number" ? valor : numeroEscrito(valor);
      const campo = (
        <CampoDecimal
          id={id}
          className={`ks-field ${def.tipo === "moeda" ? "pl-9" : ""} ${borda}`}
          valor={numero}
          zeroVazio
          permiteNegativo={def.tipo === "numero"}
          casas={def.tipo === "moeda" ? 2 : undefined}
          disabled={desabilitado}
          /* Campo vazio e zero chegam iguais (0): os dois ficam como "sem valor". */
          aoMudar={(n) => aoMudar(n === 0 ? null : n)}
        />
      );
      if (def.tipo !== "moeda") return campo;
      return (
        <div className="relative">
          <span className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-sm text-[var(--ks-color-text-soft)]">R$</span>
          {campo}
        </div>
      );
    }
    case "data":
      return (
        <input
          id={id}
          type="date"
          className={`ks-field ${borda}`}
          value={typeof valor === "string" ? valor.slice(0, 10) : ""}
          disabled={desabilitado}
          onChange={(e) => aoMudar(e.target.value || null)}
        />
      );
    case "sim_nao":
      return (
        <div id={id} role="radiogroup" aria-label={def.rotulo} className="flex gap-2">
          {[
            { v: true, rotulo: "Sim" },
            { v: false, rotulo: "Não" },
          ].map((opcao) => {
            const escolhida = valor === opcao.v;
            return (
              <button
                key={opcao.rotulo}
                type="button"
                role="radio"
                aria-checked={escolhida}
                disabled={desabilitado}
                /* Clicar de novo na escolhida volta para "sem resposta". */
                onClick={() => aoMudar(escolhida ? null : opcao.v)}
                className={`ks-button ks-button-sm ${escolhida ? "ks-button-primary" : "ks-button-secondary"}`}
              >
                {opcao.rotulo}
              </button>
            );
          })}
        </div>
      );
    case "opcoes":
      return (
        <select
          id={id}
          className={`ks-field ${borda}`}
          value={typeof valor === "string" ? valor : ""}
          disabled={desabilitado}
          onChange={(e) => aoMudar(e.target.value || null)}
        >
          <option value="">Escolha…</option>
          {def.opcoes.map((opcao) => (
            <option key={opcao} value={opcao}>
              {opcao}
            </option>
          ))}
          {typeof valor === "string" && valor && !def.opcoes.includes(valor) ? <option value={valor}>{valor} (opção antiga)</option> : null}
        </select>
      );
  }
}
