/* global React, Icon, Button, Badge, Card, Drawer, Field, PageHead, EmptyState, brl,
          fmtDate, useProdutosList, useBalancos, useEmpresasList,
          DocPrintOverlay, DocCabecalhoEmpresa, DocTitulo, DocTituloSecao, DocTabelaItens */

// ─── Balanço de estoque (inventário) — módulo Estoque ────────────────────────
// O estoque dos produtos de venda está inflado há anos (a venda B2B nunca baixou
// até a correção recente) e há produto com saldo negativo. Nenhum código conserta
// isso: só contagem física. Este módulo transforma a contagem numa operação
// controlada em vez de planilha.
//
// TRÊS COISAS QUE NÃO PODEM SAIR ERRADAS — e onde cada uma está resolvida:
//
//  1. O PRIMEIRO BALANÇO NÃO ENTRA NO RESULTADO. A diferença dele é o acerto de
//     anos de venda não baixada, não prejuízo do mês. `tipo: 'acerto_inicial'`
//     separa isso de `'inventario'` (perda/sobra de verdade). Ver BAL_TIPOS.
//
//  2. CONTAGEM CEGA. A folha impressa (BalancoFolha) NÃO leva o saldo do sistema,
//     e a tela de digitação (BalancoDigitacao) só revela o saldo DEPOIS que a
//     pessoa digitou. Se o número aparece antes, ela confirma em vez de contar —
//     é o erro clássico de inventário e destrói o propósito da operação.
//
//  3. O AJUSTE USA O SALDO DA APLICAÇÃO, NÃO O DA ABERTURA. Entre abrir, contar e
//     aplicar há venda e produção. `saldo_sistema_abertura` é só referência; quem
//     decide o ajuste é o saldo lido na hora de aplicar. (A aplicação em si é a
//     próxima etapa — ainda não está implementada, de propósito.)

const BAL_STATUS = {
  aberto:   { l: 'Aberto',   tone: 'info'    },
  contado:  { l: 'Contado',  tone: 'warning' },
  aplicado: { l: 'Aplicado', tone: 'success' },
};

// O texto importa tanto quanto o valor: ela precisa ENTENDER a escolha, não só marcar.
const BAL_TIPOS = {
  acerto_inicial: {
    l: 'Acerto inicial',
    resumo: 'Corrige a base. NÃO entra no resultado.',
    texto: 'A diferença deste balanço é o acerto de anos de estoque errado — principalmente venda que nunca foi baixada. Não é perda do mês. Ele conserta o saldo dos produtos, mas o valor da diferença não deve ser lançado como prejuízo.',
  },
  inventario: {
    l: 'Inventário',
    resumo: 'Rotina. A diferença é perda/sobra de verdade.',
    texto: 'A base já está confiável e esta contagem é de rotina. O que faltar é perda real (quebra, furto, erro de separação) e o que sobrar é sobra real — o valor da diferença conta como resultado.',
  },
};

const ESCOPOS = [
  { id: 'categoria',    label: 'Categoria',        campo: 'categoria' },
  { id: 'marca',        label: 'Marca',            campo: 'marca'     },
  { id: 'linha',        label: 'Linha',            campo: 'linha'     },
  { id: 'tipo_produto', label: 'Tipo de produto',  campo: 'tipo'      },
  { id: 'selecao',      label: 'Seleção manual',   campo: null        },
];

const balUsuario = () => {
  const p = window.tmUserProfile || {};
  return p.nome || p.name || (window.tmUser && window.tmUser.email) || '';
};
const balHoje = () => new Date().toISOString().slice(0, 10);
const balFmtD = (iso) => iso ? (fmtDate(iso) || String(iso).slice(0, 10).split('-').reverse().join('/')) : '—';
const balQtd  = (n) => (Number(n) || 0).toLocaleString('pt-BR');

// Produto sem SKU NÃO ENTRA na contagem. `salvarMovimentacao` aplica o estoque
// procurando o produto pelo SKU — sem SKU a movimentação grava e o estoque não
// muda, que é o pior dos mundos: parece que ajustou e não ajustou.
const balContavel = (p) => String((p && p.sku) || '').trim() !== '';

// Recorta os produtos pelo escopo escolhido.
function balAplicarEscopo(produtos, escopoTipo, escopoValor, selecionados) {
  const lista = produtos || [];
  if (escopoTipo === 'selecao') {
    const set = selecionados instanceof Set ? selecionados : new Set(selecionados || []);
    return lista.filter(p => set.has(p.id));
  }
  const def = ESCOPOS.find(e => e.id === escopoTipo);
  if (!def || !def.campo || !escopoValor) return [];
  return lista.filter(p => String(p[def.campo] || '') === String(escopoValor));
}

// Valores distintos de um campo, pra montar o seletor do escopo.
function balValoresDe(produtos, campo) {
  const s = new Set();
  (produtos || []).forEach(p => { const v = p[campo]; if (v) s.add(String(v)); });
  return [...s].sort((a, b) => a.localeCompare(b, 'pt-BR'));
}

// Resumo da conferência. Fora do componente de propósito (helper puro e testável).
// ⚠️ `contada === null` é PENDENTE, não zero — ver numOuNull em db.js.
// Item APLICADO usa o saldo da aplicação e o ajuste GRAVADOS — é o que de fato
// aconteceu; o saldo da abertura é referência só enquanto o item não foi aplicado.
function balResumo(itens) {
  const lin = (itens || []).map(it => {
    const contada  = (it.contada === null || it.contada === undefined) ? null : Number(it.contada);
    const aplicado = !!it.aplicado && it.saldoAplicacao !== null && it.saldoAplicacao !== undefined;
    const sistema  = aplicado ? Number(it.saldoAplicacao) : (Number(it.saldoAbertura) || 0);
    const custo    = Number(it.custoUn) || 0;
    const dif      = contada === null ? null : (aplicado ? (Number(it.ajuste) || 0) : contada - sistema);
    return { ...it, contada, sistema, custo, dif, difValor: dif === null ? null : dif * custo };
  });
  const contados   = lin.filter(l => l.contada !== null);
  const pendentes  = lin.filter(l => l.contada === null);
  const divergem   = contados.filter(l => l.dif !== 0);
  return {
    linhas: lin, contados, pendentes, divergem,
    difUnidades: contados.reduce((a, l) => a + l.dif, 0),
    difValor:    contados.reduce((a, l) => a + l.difValor, 0),
    faltando:    contados.filter(l => l.dif < 0).reduce((a, l) => a + l.difValor, 0),
    sobrando:    contados.filter(l => l.dif > 0).reduce((a, l) => a + l.difValor, 0),
    // ordenado pelo IMPACTO EM REAIS — é onde ela vai querer recontar antes de aceitar
    maiores: [...divergem].sort((a, b) => Math.abs(b.difValor) - Math.abs(a.difValor)),
  };
}

// ── Abrir balanço ────────────────────────────────────────────────────────────
function BalancoAbrirForm({ produtos, empresas, onClose, onAberto }) {
  const [escopoTipo, setEscopoTipo]   = React.useState('categoria');
  const [escopoValor, setEscopoValor] = React.useState('');
  const [selecao, setSelecao]         = React.useState([]);      // ids (escopo 'selecao')
  const [buscaSel, setBuscaSel]       = React.useState('');
  const [desc, setDesc]               = React.useState('');
  const [tipo, setTipo]               = React.useState('acerto_inicial');
  const [responsavel, setResponsavel] = React.useState(balUsuario());
  const [empresaId, setEmpresaId]     = React.useState('');
  const [jaAjustados, setJaAjustados] = React.useState(null);    // Set de produto_id, null = carregando
  const [erro, setErro]               = React.useState('');
  const [salvando, setSalvando]       = React.useState(false);

  // Quais produtos JÁ passaram por um balanço aplicado. É o que define se este é
  // "o primeiro" (acerto inicial) ou já é rotina (inventário).
  React.useEffect(() => {
    let vivo = true;
    if (!window.tmSupabase) { setJaAjustados(new Set()); return; }
    window.tmSupabase.from('balanco_itens').select('produto_id').eq('aplicado', true)
      .then(({ data }) => { if (vivo) setJaAjustados(new Set((data || []).map(r => r.produto_id))); })
      .catch(() => { if (vivo) setJaAjustados(new Set()); });
    return () => { vivo = false; };
  }, []);

  React.useEffect(() => {
    const emp = window.tmEmpresaId || ((empresas || [])[0] && empresas[0].id) || '';
    setEmpresaId(emp);
  }, [empresas]);

  const escopo    = balAplicarEscopo(produtos, escopoTipo, escopoValor, selecao);
  const contaveis = escopo.filter(balContavel);
  const semSku    = escopo.filter(p => !balContavel(p));
  const inedito   = jaAjustados ? contaveis.filter(p => !jaAjustados.has(p.id)) : [];

  // Sugere o tipo assim que o recorte muda: se NENHUM produto do recorte já foi
  // ajustado, é o primeiro balanço deles → acerto inicial. Ela pode trocar.
  React.useEffect(() => {
    if (!jaAjustados || !contaveis.length) return;
    setTipo(inedito.length === contaveis.length ? 'acerto_inicial' : 'inventario');
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [escopoTipo, escopoValor, selecao.length, jaAjustados]);

  const opcoes = React.useMemo(() => {
    const def = ESCOPOS.find(e => e.id === escopoTipo);
    return (def && def.campo) ? balValoresDe(produtos, def.campo) : [];
  }, [escopoTipo, produtos]);

  const candidatosSel = React.useMemo(() => {
    const q = buscaSel.trim().toLowerCase();
    if (!q) return [];
    return (produtos || []).filter(p =>
      String(p.sku || '').toLowerCase().includes(q) ||
      String(p.nome || p.name || '').toLowerCase().includes(q)
    ).slice(0, 12);
  }, [buscaSel, produtos]);

  const podeSalvar = contaveis.length > 0 && !salvando;

  const salvar = async () => {
    setErro(''); setSalvando(true);
    const r = await window.tmDb.abrirBalanco({
      desc: desc.trim() || null, escopoTipo,
      escopoValor: escopoTipo === 'selecao' ? `${contaveis.length} produtos` : escopoValor,
      tipo, responsavel: responsavel.trim() || null, empresaId: empresaId || null,
    }, contaveis);
    setSalvando(false);
    if (r.error) { setErro(r.error.message || 'Não foi possível abrir o balanço.'); return; }
    onAberto(r.balanco);
  };

  const info = BAL_TIPOS[tipo] || BAL_TIPOS.inventario;

  return (
    <Drawer open onClose={onClose} width={640}
      eyebrow="Estoque" title="Abrir balanço"
      subtitle="Escolha o recorte a contar. Contar tudo de uma vez não funciona."
      footer={<>
        <Button variant="secondary" onClick={onClose}>Cancelar</Button>
        <Button variant="primary" icon="clipboard-check" disabled={!podeSalvar} onClick={salvar}>
          {salvando ? 'Abrindo…' : `Abrir balanço (${contaveis.length})`}
        </Button>
      </>}>

      {erro && (
        <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>
      )}

      <div className="bal-secao">Recorte</div>
      <div className="field-grid-2">
        <Field label="Recortar por">
          <select className="input" value={escopoTipo}
            onChange={e => { setEscopoTipo(e.target.value); setEscopoValor(''); setSelecao([]); }}>
            {ESCOPOS.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
          </select>
        </Field>
        {escopoTipo !== 'selecao' && (
          <Field label={(ESCOPOS.find(e => e.id === escopoTipo) || {}).label}>
            <select className="input" value={escopoValor} onChange={e => setEscopoValor(e.target.value)}>
              <option value="">Selecione…</option>
              {opcoes.map(v => <option key={v} value={v}>{v}</option>)}
            </select>
          </Field>
        )}
      </div>

      {escopoTipo === 'selecao' && (
        <>
          <Field label="Buscar produto por SKU ou nome" value={buscaSel}
            onChange={v => setBuscaSel(typeof v === 'string' ? v : v.target.value)}
            placeholder="Digite o SKU…" />
          {candidatosSel.length > 0 && (
            <div className="bal-sugestoes">
              {candidatosSel.map(p => {
                const dentro = selecao.includes(p.id);
                return (
                  <div key={p.id} className={`bal-sugestao${dentro ? ' on' : ''}`}
                    onClick={() => setSelecao(s => dentro ? s.filter(x => x !== p.id) : [...s, p.id])}>
                    <Icon name={dentro ? 'check-square' : 'square'} size={14} />
                    <span className="ref-mono">{p.sku || '—'}</span>
                    <span className="bal-sug-nome">{p.nome || p.name}</span>
                  </div>
                );
              })}
            </div>
          )}
          {selecao.length > 0 && <div className="bal-nota">{selecao.length} produto(s) selecionado(s).</div>}
        </>
      )}

      <div className="bal-secao">Identificação</div>
      <div className="field-grid-2">
        <Field label="Descrição" value={desc} onChange={v => setDesc(typeof v === 'string' ? v : v.target.value)}
          placeholder="Ex.: Contagem linha Sensations" />
        <Field label="Responsável" value={responsavel}
          onChange={v => setResponsavel(typeof v === 'string' ? v : v.target.value)} />
      </div>
      {(empresas || []).length > 1 && (
        <Field label="Empresa">
          <select className="input" value={empresaId} onChange={e => setEmpresaId(e.target.value)}>
            {(empresas || []).map(e => <option key={e.id} value={e.id}>{e.nome_fantasia || e.razao_social || e.nome}</option>)}
          </select>
        </Field>
      )}

      {/* ── A escolha que não pode sair errada ── */}
      <div className="bal-secao">Este balanço entra no resultado?</div>
      <div className="bal-tipos">
        {Object.keys(BAL_TIPOS).map(k => (
          <div key={k} className={`bal-tipo${tipo === k ? ' on' : ''}`} onClick={() => setTipo(k)}>
            <div className="bal-tipo-head">
              <Icon name={tipo === k ? 'check-circle-2' : 'circle'} size={15} />
              <b>{BAL_TIPOS[k].l}</b>
              <span className="bal-tipo-resumo">{BAL_TIPOS[k].resumo}</span>
            </div>
          </div>
        ))}
      </div>
      <div className="bal-explica"><Icon name="info" size={14} /><span>{info.texto}</span></div>

      {jaAjustados && contaveis.length > 0 && (
        <div className="bal-nota">
          {inedito.length === contaveis.length
            ? <>Nenhum destes {contaveis.length} produtos passou por um balanço aplicado ainda — por isso a sugestão é <b>acerto inicial</b>.</>
            : <>{contaveis.length - inedito.length} de {contaveis.length} produtos já foram ajustados em balanço anterior — por isso a sugestão é <b>inventário</b>.</>}
        </div>
      )}

      {/* ── O que vai (e o que não vai) pra folha ── */}
      <div className="bal-secao">O que será contado</div>
      {escopo.length === 0 ? (
        <div className="bal-nota">Escolha um recorte para ver os produtos.</div>
      ) : (
        <div className="bal-kpis">
          <div className="bal-kpi"><b>{contaveis.length}</b><span>a contar</span></div>
          <div className={`bal-kpi${semSku.length ? ' warn' : ''}`}><b>{semSku.length}</b><span>não contáveis</span></div>
        </div>
      )}

      {semSku.length > 0 && (
        <div className="bal-aviso warning">
          <Icon name="alert-triangle" size={15} />
          <div>
            <b>{semSku.length} produto(s) ficam de fora: não têm SKU.</b>
            <div style={{ marginTop: 4 }}>
              O ajuste de estoque é aplicado procurando o produto pelo SKU. Sem SKU a
              movimentação seria gravada e o estoque não mudaria — pior do que não contar.
              Cadastre o SKU em <b>Estoque › Produtos › Lista</b> e reabra o balanço.
            </div>
            <ul className="bal-lista-sem-sku">
              {semSku.slice(0, 12).map(p => <li key={p.id}>{p.nome || p.name || p.id}</li>)}
              {semSku.length > 12 && <li className="muted">…e mais {semSku.length - 12}.</li>}
            </ul>
          </div>
        </div>
      )}
    </Drawer>
  );
}

// ── Folha de contagem (A4, CEGA) ─────────────────────────────────────────────
// ⚠️ NÃO IMPRIMA O SALDO DO SISTEMA AQUI. Se o número aparece na folha, a pessoa
// confirma em vez de contar. A folha leva SKU, descrição, unidade e um campo em
// branco — nada mais. Usa o DocImpressao.jsx sem alterá-lo.
function BalancoFolha({ balanco, itens, prodById, empresa, onClose }) {
  const emp = empresa || window.tmEmpresa || (window.tmEmpresas || [])[0] || {};
  const nomeDe = (it) => { const p = prodById[it.produtoId] || {}; return p.nome || p.name || '—'; };
  const unDe   = (it) => { const p = prodById[it.produtoId] || {}; return p.unidade || 'UN'; };
  const lista  = [...(itens || [])].sort((a, b) => String(a.sku || '').localeCompare(String(b.sku || ''), 'pt-BR'));

  const campoEmBranco = <div style={{ height: 17, border: '1px solid #bbb', background: '#fff' }} />;

  return (
    <DocPrintOverlay barraTitulo={`Folha de contagem — ${balanco.num || balanco.numero}`} onClose={onClose}>
      <DocCabecalhoEmpresa empresa={emp} />
      <DocTitulo texto="Folha de contagem de estoque" numero={balanco.num || balanco.numero} />

      <table width="100%" style={{ borderCollapse: 'collapse', marginBottom: 18 }}><tbody>
        <tr>
          <td style={{ padding: '6px 9px', border: '1px solid #ccc', fontSize: 10.5 }}>
            <b>Recorte:</b> {balanco.escopoValor || balanco.escopo_valor || '—'}
            {balanco.desc || balanco.descricao ? ` · ${balanco.desc || balanco.descricao}` : ''}
          </td>
          <td style={{ padding: '6px 9px', border: '1px solid #ccc', fontSize: 10.5, width: '32%' }}>
            <b>Aberto em:</b> {balFmtD(balanco.dataAbertura || balanco.created_at)}
          </td>
        </tr>
        <tr>
          <td colSpan={2} style={{ padding: '6px 9px', border: '1px solid #ccc', fontSize: 10.5 }}>
            <b>Contado por:</b> ______________________________&nbsp;&nbsp;&nbsp;
            <b>Data da contagem:</b> ______ / ______ / __________
          </td>
        </tr>
      </tbody></table>

      <DocTituloSecao>Conte a prateleira e escreva a quantidade encontrada</DocTituloSecao>
      <DocTabelaItens
        colunas={[
          { label: 'Código / SKU', width: 95 },
          { label: 'Descrição do produto' },
          { label: 'Un.', width: 40, align: 'center' },
          { label: 'Quantidade contada', width: 120, align: 'center' },
        ]}
        linhas={lista.map(it => [
          { v: it.sku || '—', muted: true },
          { v: nomeDe(it) },
          { v: unDe(it), align: 'center' },
          { v: campoEmBranco },
        ])}
        totais={[['Linhas a contar', balQtd(lista.length), true]]}
      />

      {/* Instrução no papel: sem ela, item não contado vira zero na cabeça de quem digita. */}
      <div style={{ fontSize: 10, color: '#555', lineHeight: 1.6, border: '1px solid #ddd', padding: '9px 11px' }}>
        <b>Como preencher:</b> escreva a quantidade encontrada na prateleira, em números.
        Se não houver nenhuma unidade, escreva <b>0</b> (zero). Se você <b>não conseguiu contar</b> o
        item, <b>deixe em branco</b> — em branco é diferente de zero: zero manda o sistema zerar o
        saldo, em branco deixa o item pendente e o saldo intacto.
      </div>
    </DocPrintOverlay>
  );
}

// ── Digitação (o saldo do sistema fica escondido até ela digitar) ────────────
function BalancoDigitacao({ balanco, itens, prodById, onClose, onMudou }) {
  const [linhas, setLinhas]   = React.useState(itens || []);
  const [busca, setBusca]     = React.useState('');
  const [foco, setFoco]       = React.useState(null);     // item sendo digitado
  const [valor, setValor]     = React.useState('');
  const [ultimo, setUltimo]   = React.useState(null);     // { item, contada, sistema, dif } — revelado
  const [erro, setErro]       = React.useState('');
  const [salvando, setSalvando] = React.useState(false);
  const buscaRef = React.useRef(null);

  React.useEffect(() => { if (buscaRef.current) buscaRef.current.focus(); }, []);

  const nomeDe = (it) => { const p = prodById[it.produtoId] || {}; return p.nome || p.name || '—'; };
  const unDe   = (it) => { const p = prodById[it.produtoId] || {}; return p.unidade || 'UN'; };

  const achados = React.useMemo(() => {
    const q = busca.trim().toLowerCase();
    if (!q) return [];
    return linhas.filter(it =>
      String(it.sku || '').toLowerCase().includes(q) ||
      nomeDe(it).toLowerCase().includes(q)
    ).slice(0, 8);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [busca, linhas]);

  const escolher = (it) => {
    // Item aplicado é imutável: recontar aqui mudaria o número na tela e nunca
    // chegaria ao estoque (a aplicação pula item já aplicado). db.js tem a mesma
    // trava no update — esta é só a versão educada.
    if (it.aplicado) { setErro(`${it.sku} já foi aplicado — a contagem dele não pode mais mudar.`); return; }
    setFoco(it);
    setValor(it.contada === null || it.contada === undefined ? '' : String(it.contada));
    setUltimo(null); setErro('');
  };

  const gravar = async () => {
    if (!foco) return;
    const txt = String(valor).trim();
    if (txt === '') { setErro('Digite a quantidade contada, ou 0 se a prateleira estiver vazia.'); return; }
    const n = Number(txt.replace(',', '.'));
    if (isNaN(n) || n < 0) { setErro('Quantidade inválida.'); return; }

    setSalvando(true); setErro('');
    const r = await window.tmDb.salvarContagem(foco.id, n, balUsuario());
    setSalvando(false);
    if (r.error) { setErro(r.error.message || 'Não foi possível gravar a contagem.'); return; }

    setLinhas(ls => ls.map(l => l.id === r.item.id ? r.item : l));
    // SÓ AGORA o saldo do sistema aparece — depois de ela ter comprometido o número.
    const sistema = Number(foco.saldoAbertura) || 0;
    setUltimo({ item: r.item, nome: nomeDe(foco), contada: n, sistema, dif: n - sistema });
    setFoco(null); setValor(''); setBusca('');
    if (buscaRef.current) buscaRef.current.focus();
    onMudou && onMudou();
  };

  const limpar = async (it) => {
    setSalvando(true);
    const r = await window.tmDb.salvarContagem(it.id, null, balUsuario());
    setSalvando(false);
    if (r.error) { setErro(r.error.message || 'Não foi possível apagar a contagem.'); return; }
    setLinhas(ls => ls.map(l => l.id === r.item.id ? r.item : l));
    setUltimo(null);
    onMudou && onMudou();
  };

  const contados  = linhas.filter(l => l.contada !== null && l.contada !== undefined);
  const pendentes = linhas.filter(l => l.contada === null || l.contada === undefined);

  // aberto → contado quando a digitação termina (e volta se uma contagem for
  // apagada). Nunca mexe num balanço já aplicado.
  const fechar = async () => {
    if (balanco.status !== 'aplicado' && window.tmSupabase) {
      const novo = (linhas.length > 0 && pendentes.length === 0) ? 'contado' : 'aberto';
      if (novo !== balanco.status) {
        await window.tmSupabase.from('balancos')
          .update({ status: novo, updated_at: new Date().toISOString() }).eq('id', balanco.id);
      }
    }
    onClose();
  };

  return (
    <Drawer open onClose={fechar} width={720}
      eyebrow={`Balanço ${balanco.num || balanco.numero}`} title="Digitar contagem"
      subtitle="O saldo do sistema só aparece depois que você digitar. É de propósito."
      footer={<Button variant="secondary" onClick={fechar}>Fechar</Button>}>

      <div className="bal-kpis">
        <div className="bal-kpi"><b>{contados.length}</b><span>contados</span></div>
        <div className={`bal-kpi${pendentes.length ? ' warn' : ''}`}><b>{pendentes.length}</b><span>pendentes</span></div>
      </div>

      <Field label="Buscar por SKU">
        <input ref={buscaRef} className="input" value={busca} placeholder="Digite o SKU e tecle Enter…"
          onChange={e => setBusca(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter' && achados.length === 1) escolher(achados[0]); }} />
      </Field>

      {achados.length > 0 && !foco && (
        <div className="bal-sugestoes">
          {achados.map(it => (
            <div key={it.id} className="bal-sugestao" onClick={() => escolher(it)}>
              <span className="ref-mono">{it.sku}</span>
              <span className="bal-sug-nome">{nomeDe(it)}</span>
              {/* SEM SALDO AQUI — só o estado da contagem */}
              {(it.contada !== null && it.contada !== undefined)
                ? <Badge tone="success">contado</Badge>
                : <span className="muted" style={{ fontSize: 11 }}>pendente</span>}
            </div>
          ))}
        </div>
      )}

      {foco && (
        <div className="bal-contagem">
          <div className="bal-contagem-head">
            <span className="ref-mono gold">{foco.sku}</span>
            <b>{nomeDe(foco)}</b>
            <span className="muted">{unDe(foco)}</span>
          </div>
          {/* ⚠️ nenhum saldo do sistema neste bloco — é o ponto da contagem cega */}
          <div className="bal-contagem-input">
            <Field label="Quantidade contada">
              <input className="input" autoFocus inputMode="decimal" value={valor}
                placeholder="0"
                onChange={e => setValor(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') gravar(); }} />
            </Field>
            <Button variant="primary" icon="check" disabled={salvando} onClick={gravar}>
              {salvando ? 'Gravando…' : 'Gravar'}
            </Button>
            <Button variant="ghost" onClick={() => { setFoco(null); setValor(''); setErro(''); }}>Cancelar</Button>
          </div>
          <div className="bal-nota">Prateleira vazia é <b>0</b>. Não conseguiu contar? Não grave — deixe pendente.</div>
        </div>
      )}

      {erro && <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>}

      {/* Revelação: só depois de gravar */}
      {ultimo && (
        <div className={`bal-revela ${ultimo.dif === 0 ? 'ok' : ultimo.dif > 0 ? 'sobra' : 'falta'}`}>
          <div className="bal-revela-nome">{ultimo.item.sku} · {ultimo.nome}</div>
          <div className="bal-revela-nums">
            <div><span>Contado</span><b>{balQtd(ultimo.contada)}</b></div>
            <div><span>Sistema</span><b>{balQtd(ultimo.sistema)}</b></div>
            <div><span>Diferença</span><b>{ultimo.dif > 0 ? '+' : ''}{balQtd(ultimo.dif)}</b></div>
          </div>
        </div>
      )}

      <div className="bal-secao">Já contados ({contados.length})</div>
      {contados.length === 0 ? (
        <div className="bal-nota">Nada contado ainda.</div>
      ) : (
        <table className="tbl bal-tbl">
          <thead><tr><th>SKU</th><th>Produto</th><th className="num right">Contado</th><th className="num right">Sistema</th><th className="num right">Dif.</th><th></th></tr></thead>
          <tbody>
            {contados.map(it => {
              const c = Number(it.contada), s = Number(it.saldoAbertura) || 0, d = c - s;
              return (
                <tr key={it.id}>
                  <td><span className="ref-mono">{it.sku}</span></td>
                  <td>{nomeDe(it)}</td>
                  <td className="num right">{balQtd(c)}</td>
                  <td className="num right muted">{balQtd(s)}</td>
                  <td className="num right" style={{ color: d === 0 ? 'var(--tm-fg-3)' : d > 0 ? 'var(--tm-success)' : 'var(--tm-danger)', fontWeight: 600 }}>
                    {d > 0 ? '+' : ''}{balQtd(d)}
                  </td>
                  <td>{it.aplicado
                    ? <Badge tone="success">aplicado</Badge>
                    : <Button variant="ghost" size="sm" icon="rotate-ccw" title="Apagar a contagem (volta a pendente)"
                        disabled={salvando} onClick={() => limpar(it)} />}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      )}

      {/* Pendentes SEM saldo: quem ainda vai contar não pode ver o número */}
      <div className="bal-secao">Pendentes ({pendentes.length})</div>
      {pendentes.length === 0 ? (
        <div className="bal-nota">Todos os itens foram contados.</div>
      ) : (
        <table className="tbl bal-tbl">
          <thead><tr><th>SKU</th><th>Produto</th><th>Un.</th><th></th></tr></thead>
          <tbody>
            {pendentes.map(it => (
              <tr key={it.id} className="clickable" onClick={() => escolher(it)}>
                <td><span className="ref-mono">{it.sku}</span></td>
                <td>{nomeDe(it)}</td>
                <td className="muted">{unDe(it)}</td>
                <td><Button variant="ghost" size="sm" icon="pencil" title="Contar este" onClick={() => escolher(it)} /></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </Drawer>
  );
}

// ── Aplicar (a única etapa que mexe no estoque de verdade) ───────────────────
// Cada item passa por tmDb.aplicarItemBalanco (ordem: retomada? → relê saldo →
// grava ajuste → movimentação com id do item → marca aplicado). Antes de rodar,
// esta tela procura movimentação de cada produto ENTRE a contagem e agora — se
// houver, lista e OBRIGA a escolha por item: aplicar mesmo assim ou deixar de
// fora pra recontar. A escolha é dela; o silêncio é que não pode.
function BalancoAplicar({ balanco, itens, prodById, onClose, onFeito }) {
  const [movsPorItem, setMovsPorItem] = React.useState(null);   // { itemId: [movs] } — null = carregando
  const [decisoes, setDecisoes]       = React.useState({});     // { itemId: 'aplicar' | 'recontar' }
  const [rodando, setRodando]         = React.useState(false);
  const [progresso, setProgresso]     = React.useState(null);   // { feito, total, atual }
  const [resultado, setResultado]     = React.useState(null);
  const [erro, setErro]               = React.useState(null);   // { sku, msg, feitos }

  const nomeDe = (it) => { const p = prodById[it.produtoId] || {}; return p.nome || p.name || '—'; };
  const ehContado  = (it) => it.contada !== null && it.contada !== undefined;
  const contados   = (itens || []).filter(ehContado);
  const pendentes  = (itens || []).filter(it => !ehContado(it));
  const jaFeitos   = contados.filter(it => it.aplicado);
  const aAplicar   = contados.filter(it => !it.aplicado);
  const numero     = balanco.num || balanco.numero || '';

  // Movimentações entre o contado_em de cada item e agora — fora as do próprio
  // balanço (na retomada, o ajuste já aplicado apareceria como "venda no meio").
  React.useEffect(() => {
    let vivo = true;
    (async () => {
      if (!window.tmSupabase || !aAplicar.length) { if (vivo) setMovsPorItem({}); return; }
      const skus = [...new Set(aAplicar.map(it => it.sku))];
      const desdeMin = aAplicar.map(it => it.contadoEm).filter(Boolean).sort()[0];
      let q = window.tmSupabase.from('movimentacoes_estoque')
        .select('id, sku, tipo, motivo, quantidade, quando, pedido_ref').in('sku', skus);
      if (desdeMin) q = q.gte('quando', desdeMin);
      const { data } = await q;
      const mapa = {};
      aAplicar.forEach(it => {
        const desde = it.contadoEm ? new Date(it.contadoEm).getTime() : 0;
        mapa[it.id] = (data || []).filter(m =>
          m.sku === it.sku && m.id !== it.id && m.pedido_ref !== numero &&
          m.quando && new Date(m.quando).getTime() > desde);
      });
      if (vivo) setMovsPorItem(mapa);
    })();
    return () => { vivo = false; };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const comMov  = movsPorItem ? aAplicar.filter(it => (movsPorItem[it.id] || []).length > 0) : [];
  const decidir = (id, v) => setDecisoes(d => ({ ...d, [id]: v }));
  const faltaDecidir = comMov.filter(it => !decisoes[it.id]);
  const pode = movsPorItem !== null && aAplicar.length + jaFeitos.length > 0 &&
               faltaDecidir.length === 0 && !rodando && !resultado;

  const aplicar = async () => {
    setErro(null); setRodando(true);
    const deixados = aAplicar.filter(it => decisoes[it.id] === 'recontar');
    // jaFeitos entram na fila de propósito: é a retomada — o aplicarItemBalanco
    // os pula ou fecha o que faltou, e o balanço só finaliza depois disso.
    const fila = [...jaFeitos, ...aAplicar.filter(it => decisoes[it.id] !== 'recontar')];
    const feitos = [];
    for (const it of fila) {
      setProgresso({ feito: feitos.length, total: fila.length, atual: it.sku });
      let r;
      try { r = await window.tmDb.aplicarItemBalanco(balanco, it, balUsuario()); }
      catch (e) { r = { error: e }; }
      if (r.error) {
        setErro({ sku: it.sku, msg: r.error.message || String(r.error), feitos: feitos.length });
        setRodando(false); setProgresso(null); onFeito && onFeito();
        return;
      }
      feitos.push({ it, r });
    }
    let statusFinal = balanco.status;
    if (deixados.length === 0) {
      await window.tmSupabase.from('balancos')
        .update({ status: 'aplicado', data_aplicacao: new Date().toISOString(), updated_at: new Date().toISOString() })
        .eq('id', balanco.id);
      statusFinal = 'aplicado';
    }
    setResultado({
      movimentos: feitos.filter(f => f.r.ok && f.r.ajuste !== 0).length,
      batidos:    feitos.filter(f => f.r.ok && f.r.ajuste === 0).length,
      retomados:  feitos.filter(f => f.r.retomado || f.r.pulado === 'ja_aplicado').length,
      deixados, statusFinal,
    });
    setRodando(false); setProgresso(null);
    onFeito && onFeito();
  };

  const info = BAL_TIPOS[balanco.tipo] || BAL_TIPOS.inventario;

  return (
    <Drawer open onClose={onClose} width={720}
      eyebrow={`Balanço ${numero}`} title="Aplicar ajustes"
      subtitle="Gera uma movimentação de ajuste por item divergente. Nada do histórico é apagado."
      footer={<>
        <Button variant="secondary" onClick={onClose}>{resultado ? 'Fechar' : 'Cancelar'}</Button>
        {!resultado && (
          <Button variant="primary" icon={erro ? 'rotate-ccw' : 'check-check'} disabled={!pode && !erro} onClick={aplicar}>
            {rodando ? 'Aplicando…' : erro ? 'Tentar de novo (retoma do ponto)' :
             jaFeitos.length ? 'Retomar aplicação' : 'Aplicar agora'}
          </Button>
        )}
      </>}>

      {movsPorItem === null && <div className="bal-nota">Conferindo movimentações recentes…</div>}

      {movsPorItem !== null && !resultado && (
        <>
          <div className="bal-kpis quatro">
            <div className="bal-kpi"><b>{aAplicar.length}</b><span>a aplicar</span></div>
            <div className="bal-kpi"><b>{jaFeitos.length}</b><span>já aplicados</span></div>
            <div className={`bal-kpi${pendentes.length ? ' warn' : ''}`}><b>{pendentes.length}</b><span>pendentes (de fora)</span></div>
            <div className={`bal-kpi${comMov.length ? ' warn' : ''}`}><b>{comMov.length}</b><span>com mov. no meio</span></div>
          </div>

          {jaFeitos.length > 0 && (
            <div className="bal-aviso info">
              <Icon name="info" size={15} />
              <div><b>Retomada:</b> {jaFeitos.length} item(ns) já aplicados numa tentativa anterior
                serão conferidos e pulados — o ajuste deles não dobra.</div>
            </div>
          )}

          {comMov.map(it => {
            const movs = movsPorItem[it.id] || [];
            return (
              <div className="bal-aviso warning" key={it.id}>
                <Icon name="alert-triangle" size={15} />
                <div style={{ flex: 1 }}>
                  <b>{it.sku} · {nomeDe(it)} — movimentação DEPOIS da contagem</b>
                  <ul className="bal-mov-lista">
                    {movs.map(m => (
                      <li key={m.id}>{m.tipo}{m.motivo ? ` · ${m.motivo}` : ''} · {Number(m.quantidade) > 0 ? '+' : ''}{balQtd(m.quantidade)} un · {balFmtD(m.quando)}</li>
                    ))}
                  </ul>
                  <div style={{ margin: '4px 0 6px' }}>
                    Se essa mercadoria saiu (ou entrou) da prateleira <b>depois</b> de contada, o
                    número contado está velho — aplicar assim desfaz a movimentação. Recontar é o seguro.
                  </div>
                  <label className="bal-radio">
                    <input type="radio" name={`dec-${it.id}`} checked={decisoes[it.id] === 'aplicar'}
                      onChange={() => decidir(it.id, 'aplicar')} />
                    Aplicar mesmo assim (o contado vale: estoque vira {balQtd(it.contada)})
                  </label>
                  <label className="bal-radio">
                    <input type="radio" name={`dec-${it.id}`} checked={decisoes[it.id] === 'recontar'}
                      onChange={() => decidir(it.id, 'recontar')} />
                    Deixar de fora para recontar (o balanço continua aberto pra este item)
                  </label>
                </div>
              </div>
            );
          })}
          {faltaDecidir.length > 0 && (
            <div className="bal-nota"><b>Decida os {faltaDecidir.length} item(ns) acima</b> para liberar a aplicação.</div>
          )}

          {progresso && (
            <div className="bal-nota">Aplicando {progresso.feito + 1} de {progresso.total} — {progresso.atual}…</div>
          )}

          {erro && (
            <div className="bal-aviso danger">
              <Icon name="alert-circle" size={15} />
              <div>
                <b>Parou no item {erro.sku}:</b> {erro.msg}
                <div style={{ marginTop: 4 }}>
                  Os {erro.feitos} anteriores ficaram aplicados e marcados — nada dobra.
                  <b> Tentar de novo</b> retoma exatamente do ponto onde parou.
                </div>
              </div>
            </div>
          )}
        </>
      )}

      {resultado && (
        <>
          <div className="bal-kpis quatro">
            <div className="bal-kpi"><b>{resultado.movimentos}</b><span>ajustes gerados</span></div>
            <div className="bal-kpi"><b>{resultado.batidos}</b><span>batidos (sem ajuste)</span></div>
            <div className="bal-kpi"><b>{resultado.retomados}</b><span>retomados</span></div>
            <div className={`bal-kpi${resultado.deixados.length ? ' warn' : ''}`}><b>{resultado.deixados.length}</b><span>pra recontar</span></div>
          </div>

          {resultado.statusFinal === 'aplicado' ? (
            <div className="bal-aviso info"><Icon name="lock" size={15} />
              <div><b>Balanço aplicado.</b> A partir de agora ele é somente leitura — fica no
                histórico como o documento da operação: quem contou, quando, o que divergiu.</div>
            </div>
          ) : (
            <div className="bal-aviso warning"><Icon name="alert-triangle" size={15} />
              <div><b>O balanço continua em contagem:</b> {resultado.deixados.length} item(ns) ficaram
                de fora para recontagem ({resultado.deixados.map(d => d.sku).join(', ')}).
                Reconte-os em <b>Digitar contagem</b> e aplique de novo — só os que faltam entram.</div>
            </div>
          )}

          {/* ⚠️ NADA é lançado no financeiro automaticamente. Mostrar e orientar, só. */}
          {balanco.tipo === 'acerto_inicial' ? (
            <div className="bal-explica neutro"><Icon name="shield" size={14} />
              <span><b>Acerto inicial — fora do resultado.</b> {info.texto} <b>Não lance</b> este
                valor no financeiro: nenhum título foi (nem deve ser) gerado.</span>
            </div>
          ) : (
            <div className="bal-explica atencao"><Icon name="trending-down" size={14} />
              <span><b>Inventário — perda/sobra real.</b> {info.texto} Nenhum lançamento foi feito
                automaticamente: se você quiser que a perda apareça no resultado (DRE), lance-a em
                <b> Financeiro › Contas a Pagar</b> na categoria adequada — a decisão é sua.</span>
            </div>
          )}
        </>
      )}
    </Drawer>
  );
}

// ── Conferência (antes de aplicar) ───────────────────────────────────────────
function BalancoConferencia({ balanco, itens, prodById, onClose, onAplicar }) {
  const r = balResumo(itens);
  const nomeDe = (it) => { const p = prodById[it.produtoId] || {}; return p.nome || p.name || '—'; };
  const info = BAL_TIPOS[balanco.tipo] || BAL_TIPOS.inventario;
  const aplicado = balanco.status === 'aplicado';

  return (
    <Drawer open onClose={onClose} width={760}
      eyebrow={`Balanço ${balanco.num || balanco.numero}`} title="Conferência"
      subtitle={aplicado
        ? `Aplicado em ${balFmtD(balanco.dataAplicacao)} — somente leitura.`
        : 'Confira antes de aplicar. Depois de aplicado, o balanço é somente leitura.'}
      footer={<>
        <Button variant="secondary" onClick={onClose}>Fechar</Button>
        {!aplicado && onAplicar && r.contados.length > 0 && (
          <Button variant="primary" icon="check-check" onClick={onAplicar}>Aplicar ajustes…</Button>
        )}
      </>}>

      <div className="bal-kpis quatro">
        <div className="bal-kpi"><b>{r.contados.length}</b><span>contados</span></div>
        <div className={`bal-kpi${r.pendentes.length ? ' warn' : ''}`}><b>{r.pendentes.length}</b><span>pendentes</span></div>
        <div className="bal-kpi"><b>{r.divergem.length}</b><span>divergiram</span></div>
        <div className="bal-kpi"><b>{r.difUnidades > 0 ? '+' : ''}{balQtd(r.difUnidades)}</b><span>un. de diferença</span></div>
      </div>

      <div className="bal-secao">Diferença em reais</div>
      <div className="bal-valores">
        <div className="bal-valor falta"><span>Faltando</span><b>R$ {brl(Math.abs(r.faltando))}</b></div>
        <div className="bal-valor sobra"><span>Sobrando</span><b>R$ {brl(r.sobrando)}</b></div>
        <div className={`bal-valor ${r.difValor < 0 ? 'falta' : 'sobra'} total`}>
          <span>Saldo</span><b>{r.difValor < 0 ? '−' : '+'} R$ {brl(Math.abs(r.difValor))}</b>
        </div>
      </div>

      <div className={`bal-explica ${balanco.tipo === 'acerto_inicial' ? 'neutro' : 'atencao'}`}>
        <Icon name={balanco.tipo === 'acerto_inicial' ? 'shield' : 'trending-down'} size={14} />
        <span><b>{info.l}.</b> {info.texto}</span>
      </div>

      {r.pendentes.length > 0 && (
        <div className="bal-aviso warning">
          <Icon name="alert-triangle" size={15} />
          <div>
            <b>{r.pendentes.length} item(ns) sem contagem.</b>
            <div style={{ marginTop: 4 }}>
              Item pendente <b>não é zero</b> — ele fica de fora do ajuste e o saldo
              atual continua valendo. Se algum deles deveria ter sido contado, volte
              em <b>Digitar contagem</b> antes de aplicar.
            </div>
          </div>
        </div>
      )}

      {/* Onde ela vai querer recontar: as maiores divergências EM VALOR */}
      <div className="bal-secao">Maiores divergências (por valor)</div>
      {r.maiores.length === 0 ? (
        <div className="bal-nota">Nenhuma divergência entre o contado e o sistema.</div>
      ) : (
        <table className="tbl bal-tbl">
          <thead><tr><th>SKU</th><th>Produto</th><th className="num right">Contado</th><th className="num right">Sistema</th><th className="num right">Dif.</th><th className="num right">Em R$</th></tr></thead>
          <tbody>
            {r.maiores.map(l => (
              <tr key={l.id}>
                <td><span className="ref-mono">{l.sku}</span></td>
                <td>{nomeDe(l)}</td>
                <td className="num right">{balQtd(l.contada)}</td>
                <td className="num right muted">{balQtd(l.sistema)}</td>
                <td className="num right" style={{ color: l.dif > 0 ? 'var(--tm-success)' : 'var(--tm-danger)', fontWeight: 600 }}>
                  {l.dif > 0 ? '+' : ''}{balQtd(l.dif)}
                </td>
                <td className="num right cell-money" style={{ color: l.difValor > 0 ? 'var(--tm-success)' : 'var(--tm-danger)' }}>
                  {l.difValor < 0 ? '−' : '+'} R$ {brl(Math.abs(l.difValor))}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      {/* ⚠️ Antes de aplicar, os números usam o saldo da ABERTURA (referência).
          Depois, usam o saldo da APLICAÇÃO e o ajuste gravados — o que aconteceu. */}
      {aplicado ? (
        <div className="bal-aviso info">
          <Icon name="lock" size={15} />
          <div>Números da <b>aplicação</b>: saldo lido no momento de aplicar e o ajuste
            que de fato foi gerado. Este é o documento da operação.</div>
        </div>
      ) : (
        <div className="bal-aviso info">
          <Icon name="info" size={15} />
          <div>
            As diferenças acima usam o saldo <b>da abertura</b> do balanço, como referência.
            Na hora de aplicar, o sistema relê o saldo <b>daquele momento</b> e recalcula —
            senão o ajuste apagaria as vendas e produções que aconteceram no meio.
          </div>
        </div>
      )}
    </Drawer>
  );
}

// ── Lista / página do módulo ────────────────────────────────────────────────
function Balancos({ onNav }) {   // eslint-disable-line no-unused-vars
  const bals = useBalancos();
  const prodHook = useProdutosList([]);
  const empresasHook = useEmpresasList([]);
  const [abrindo, setAbrindo] = React.useState(false);
  const [folha, setFolha]     = React.useState(null);   // { balanco, itens }
  const [digitar, setDigitar] = React.useState(null);
  const [conferir, setConferir] = React.useState(null);
  const [aplicar, setAplicar]   = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  const prodById = {}; (prodHook.rows || []).forEach(p => { prodById[p.id] = p; });
  // Sem filtro de status de propósito: produto Inativo/Descontinuado com sobra na
  // prateleira também precisa ser contado — o balanço mede a realidade física.
  const produtos = prodHook.rows || [];

  const abrirCom = async (bal, setter) => {
    setBusy(true);
    const d = await window.tmDb.loadBalanco(bal.id);
    setBusy(false);
    setter({ balanco: bal, itens: d.itens });
  };

  const rows = bals.rows || [];

  return (
    <div className="canvas">
      <PageHead title="Estoque · Balanço de estoque"
        sub={`${rows.length} balanço${rows.length !== 1 ? 's' : ''}`}
        right={<Button variant="primary" icon="clipboard-check" size="sm" onClick={() => setAbrindo(true)}>Abrir balanço</Button>} />

      <Card>
        {rows.length === 0 ? (
          <EmptyState icon="clipboard-check" title="Nenhum balanço ainda"
            msg="O balanço é a contagem física: você conta a prateleira, o sistema mostra a diferença e só então o ajuste é gerado — sem apagar nada do histórico. Comece por um recorte pequeno (uma linha, uma categoria)."
            action={<Button variant="primary" size="sm" icon="clipboard-check" onClick={() => setAbrindo(true)}>Abrir o primeiro</Button>} />
        ) : (
          <table className="tbl">
            <thead><tr><th>Nº</th><th>Recorte</th><th>Tipo</th><th>Aberto em</th><th>Responsável</th><th>Status</th><th></th></tr></thead>
            <tbody>
              {rows.map(b => {
                const st = BAL_STATUS[b.status] || BAL_STATUS.aberto;
                const tp = BAL_TIPOS[b.tipo] || BAL_TIPOS.inventario;
                return (
                  <tr key={b.id} className="clickable" onClick={() => abrirCom(b, setConferir)}>
                    <td><span className="ref-mono gold">{b.num}</span></td>
                    <td>{b.escopoValor || '—'}{b.desc ? <span className="muted"> · {b.desc}</span> : null}</td>
                    <td><Badge tone={b.tipo === 'acerto_inicial' ? 'info' : 'neutral'}>{tp.l}</Badge></td>
                    <td className="muted">{balFmtD(b.dataAbertura || b.created_at)}</td>
                    <td className="muted">{b.responsavel || '—'}</td>
                    <td><Badge tone={st.tone}>{st.l}</Badge></td>
                    <td onClick={e => e.stopPropagation()} style={{ whiteSpace: 'nowrap' }}>
                      <Button variant="ghost" size="sm" icon="printer" disabled={busy} title="Folha de contagem (cega)" onClick={() => abrirCom(b, setFolha)} />
                      {b.status !== 'aplicado' && <Button variant="ghost" size="sm" icon="keyboard" disabled={busy} title="Digitar contagem" onClick={() => abrirCom(b, setDigitar)} />}
                      <Button variant="ghost" size="sm" icon="list-checks" disabled={busy} title="Conferir" onClick={() => abrirCom(b, setConferir)} />
                      {b.status !== 'aplicado' && <Button variant="ghost" size="sm" icon="check-check" disabled={busy} title="Aplicar ajustes" onClick={() => abrirCom(b, setAplicar)} />}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Card>

      {abrindo && <BalancoAbrirForm produtos={produtos} empresas={empresasHook.rows || []}
        onClose={() => setAbrindo(false)}
        onAberto={(b) => { setAbrindo(false); bals.reload(); abrirCom(b, setFolha); }} />}

      {folha && <BalancoFolha balanco={folha.balanco} itens={folha.itens} prodById={prodById}
        empresa={(empresasHook.rows || []).find(e => e.id === folha.balanco.empresaId)}
        onClose={() => setFolha(null)} />}

      {digitar && <BalancoDigitacao balanco={digitar.balanco} itens={digitar.itens} prodById={prodById}
        onClose={() => { setDigitar(null); bals.reload(); }} onMudou={() => {}} />}

      {conferir && <BalancoConferencia balanco={conferir.balanco} itens={conferir.itens} prodById={prodById}
        onClose={() => setConferir(null)}
        onAplicar={() => { const b = conferir.balanco; setConferir(null); abrirCom(b, setAplicar); }} />}

      {aplicar && <BalancoAplicar balanco={aplicar.balanco} itens={aplicar.itens} prodById={prodById}
        onClose={() => setAplicar(null)}
        onFeito={() => { bals.reload(); prodHook.reload && prodHook.reload(); }} />}
    </div>
  );
}

Object.assign(window, {
  Balancos, BalancoAbrirForm, BalancoFolha, BalancoDigitacao, BalancoConferencia, BalancoAplicar,
  balResumo, balAplicarEscopo, balValoresDe, balContavel, BAL_TIPOS, BAL_STATUS,
});
