/* Vista TABELA — desktop-first 1440px. Abas: Estoque atual · Movimentações. + Ajuste sheet. */

// Estado de filtros persistente entre remontagens (protótipo)
const TAB_STATE = {
  aba: 'estoque',
  est: { busca: '', gal: 'todos', cat: 'todos', pontas: false, rascunho: false, validade: 'todos', sortKey: 'pos', sortDir: 'asc' },
  mov: { busca: '', tipo: 'todos', operador: 'todos', venda: '', sortKey: 'data', sortDir: 'desc' },
};

function parseData(quando, hora) {
  if (!quando || quando === 'agora') return 99999999;
  if (quando === 'hoje') return 99999998;
  const p = quando.split('/');
  const dia = parseInt(p[0], 10), mes = parseInt(p[1], 10);
  const h = hora ? parseInt(hora.replace(':', ''), 10) : 0;
  return mes * 1000000 + dia * 10000 + h;
}

function StatusPill({ pal }) {
  if (pal.foraDePosicao) return <span className="tpill fora"><EIcon name="alert" size={11} /> FORA DE POSIÇÃO</span>;
  if (ESTQ.isMat(pal)) {
    const e = ESTQ.validadeEstado(pal.validade);
    if (e && e.st === 'vencido') return <span className="tpill venc">Vencido</span>;
    if (e && e.st === 'breve') return <span className="tpill breve">Vence breve</span>;
    return <span className="tpill normal">Normal</span>;
  }
  if (pal.status === 'ponta_sugerida') return <span className="tpill sug">PONTA?</span>;
  if (pal.status === 'ponta') return <span className="tpill ponta">PONTA</span>;
  return <span className="tpill normal">Normal</span>;
}

/* ===== Linhas do Estoque atual ===== */
function buildEstoque(db) {
  const rows = [];
  Object.values(db.pallets).forEach((pal) => {
    if (pal.arquivado) return;
    const pos = ESTQ.findPos(db, pal.id);
    if (!pos) return;
    const prod = ESTQ.PRODUTOS[pal.prod] || db.produtos[pal.prod];
    rows.push({
      id: pal.id, pal, prod, pos,
      posLabel: pos.rascunho ? ('Rascunho' + (pal.foraDePosicao ? ' · fora de posição' : '')) : pos.code + '·N' + pos.nivel,
      gal: pos.gal, rascunho: !!pos.rascunho,
    });
  });
  return rows;
}

function TH({ k, label, st, setSt, num }) {
  const active = st.sortKey === k;
  return (
    <th className={(num ? 'num ' : '') + (active ? 'active' : '')}
      onClick={() => setSt(Object.assign({}, st, { sortKey: k, sortDir: active && st.sortDir === 'asc' ? 'desc' : 'asc' }))}>
      <span className="th-in">{label}{active && <EIcon name="arrowUpDown" size={13} />}</span>
    </th>
  );
}

function EstoqueAtual({ db, papel, online, onLinha, onSaida, onAjuste, st, setSt }) {
  const { useState } = React;
  const [menu, setMenu] = useState(null);
  let rows = buildEstoque(db);

  // filtros
  const q = st.busca.trim().toLowerCase();
  rows = rows.filter((r) => {
    if (q && !((r.prod.nome + ' ' + r.prod.marca + ' ' + (r.prod.codigo || '') + ' ' + (r.pal.lote || '') + ' ' + r.posLabel).toLowerCase().includes(q))) return false;
    if (st.gal !== 'todos' && String(r.gal) !== st.gal) return false;
    if (st.cat !== 'todos' && r.prod.cat !== st.cat) return false;
    if (st.pontas && !(r.pal.status === 'ponta' || r.pal.status === 'ponta_sugerida')) return false;
    if (st.rascunho && !r.rascunho) return false;
    if (st.validade !== 'todos') {
      const e = ESTQ.isMat(r.pal) ? ESTQ.validadeEstado(r.pal.validade) : null;
      if (st.validade === 'vencidos' && !(e && e.st === 'vencido')) return false;
      if (st.validade === 'proximos' && !(e && e.st === 'breve')) return false;
    }
    return true;
  });

  // ordenação
  const dir = st.sortDir === 'asc' ? 1 : -1;
  rows.sort((a, b) => {
    let va, vb;
    switch (st.sortKey) {
      case 'produto': va = a.prod.nome; vb = b.prod.nome; break;
      case 'codigo': va = a.prod.codigo || ''; vb = b.prod.codigo || ''; break;
      case 'cat': va = a.prod.cat; vb = b.prod.cat; break;
      case 'lote': va = a.pal.lote || ''; vb = b.pal.lote || ''; break;
      case 'qtd': va = a.pal.cx; vb = b.pal.cx; break;
      case 'm2': va = ESTQ.palletM2Num(a.pal); vb = ESTQ.palletM2Num(b.pal); break;
      case 'gal': va = a.gal; vb = b.gal; break;
      case 'entrada': va = a.pal.entradaEm; vb = b.pal.entradaEm; break;
      default: va = a.posLabel; vb = b.posLabel;
    }
    if (va < vb) return -1 * dir;
    if (va > vb) return 1 * dir;
    return 0;
  });

  // totais do filtro
  const totCx = rows.reduce((s, r) => s + (ESTQ.isMat(r.pal) ? 0 : r.pal.cx), 0);
  const totSacos = rows.reduce((s, r) => s + (ESTQ.isMat(r.pal) ? r.pal.cx : 0), 0);
  const totM2 = rows.reduce((s, r) => s + ESTQ.palletM2Num(r.pal), 0);
  const podeAjustar = papel === 'gestor' || papel === 'escritorio';

  function copiar(txt, e) {
    e.stopPropagation();
    try { navigator.clipboard && navigator.clipboard.writeText(txt); } catch (err) { /* noop */ }
  }

  return (
    <div className="tab-conteudo">
      {/* Filtros */}
      <div className="tab-filtros">
        <div className="tf-busca">
          <EIcon name="search" size={18} />
          <input value={st.busca} onChange={(e) => setSt(Object.assign({}, st, { busca: e.target.value }))} placeholder="Buscar produto, lote, posição…" />
        </div>
        <FiltroSelect label="Galpão" value={st.gal} onChange={(v) => setSt(Object.assign({}, st, { gal: v }))}
          opcoes={[['todos', 'Todos'], ['1', 'G1'], ['2', 'G2'], ['3', 'G3']]} />
        <FiltroSelect label="Categoria" value={st.cat} onChange={(v) => setSt(Object.assign({}, st, { cat: v }))}
          opcoes={[['todos', 'Todas'], ['piso', 'Piso'], ['material', 'Material']]} />
        <FiltroSelect label="Validade" value={st.validade} onChange={(v) => setSt(Object.assign({}, st, { validade: v }))}
          opcoes={[['todos', 'Todas'], ['vencidos', 'Vencidos'], ['proximos', 'Próx. 30 dias']]} />
        <button className={'tf-toggle' + (st.pontas ? ' on' : '')} onClick={() => setSt(Object.assign({}, st, { pontas: !st.pontas }))}>Pontas</button>
        <button className={'tf-toggle' + (st.rascunho ? ' on' : '')} onClick={() => setSt(Object.assign({}, st, { rascunho: !st.rascunho }))}>Em rascunho</button>
      </div>

      {/* Tabela */}
      <div className="tab-scroll">
        <table className="tbl">
          <thead>
            <tr>
              <TH k="pos" label="Posição" st={st} setSt={setSt} />
              <TH k="produto" label="Produto" st={st} setSt={setSt} />
              <TH k="codigo" label="Código" st={st} setSt={setSt} />
              <TH k="cat" label="Categoria" st={st} setSt={setSt} />
              <TH k="lote" label="Lote" st={st} setSt={setSt} />
              <th>Ton</th><th>Bit</th>
              <TH k="qtd" label="Qtd" st={st} setSt={setSt} num />
              <TH k="m2" label="m²" st={st} setSt={setSt} num />
              <th>Validade</th>
              <th>Status</th>
              <TH k="gal" label="Galpão" st={st} setSt={setSt} />
              <TH k="entrada" label="Entrada" st={st} setSt={setSt} />
              <th className="acoes-col"></th>
            </tr>
          </thead>
          <tbody>
            {rows.map((r) => {
              const isMat = ESTQ.isMat(r.pal);
              return (
                <tr key={r.id} onClick={() => onLinha(r.id)}>
                  <td className="pos-cell">
                    <span className="pos-txt">{r.posLabel}</span>
                    <button className="copy-btn" onClick={(e) => copiar(r.pos.rascunho ? 'Rascunho G' + r.gal : r.pos.code, e)} title="Copiar"><EIcon name="copy" size={14} /></button>
                  </td>
                  <td><span className="prod-cell">{r.prod.foto ? <img className="prod-sw foto" src={r.prod.foto} alt="" /> : <span className="prod-sw" style={{ background: r.prod.cor }}></span>}{r.prod.nome}</span></td>
                  <td className="cod-cell">{r.prod.codigo || <span className="vazio-cell">—</span>}</td>
                  <td><span className={'cat-tag ' + r.prod.cat}>{isMat ? 'Material' : 'Piso'}</span></td>
                  <td>{r.pal.lote || <span className="vazio-cell">—</span>}</td>
                  <td>{isMat ? '—' : r.pal.ton}</td>
                  <td>{isMat ? '—' : r.pal.bitola}</td>
                  <td className="num">{r.pal.cx}{isMat ? ' ' + r.prod.un[1] : ' cx'}</td>
                  <td className="num">{isMat ? '—' : ESTQ.fmtNum(ESTQ.palletM2Num(r.pal))}</td>
                  <td>{isMat && r.pal.validade ? <ValChip iso={r.pal.validade} /> : <span className="vazio-cell">—</span>}</td>
                  <td><StatusPill pal={r.pal} /></td>
                  <td>G{r.gal}</td>
                  <td>{r.pal.entradaEm}</td>
                  <td className="acoes-col" onClick={(e) => e.stopPropagation()}>
                    <button className="row-menu-btn" onClick={() => setMenu(menu === r.id ? null : r.id)}><EIcon name="dots" size={18} /></button>
                    {menu === r.id && (
                      <div className="row-menu" onMouseLeave={() => setMenu(null)}>
                        <button onClick={() => { setMenu(null); onLinha(r.id); }}><EIcon name="search" size={16} /> Ver detalhe</button>
                        <button disabled={!online} onClick={() => { setMenu(null); onSaida(r.id); }}><EIcon name="truck" size={16} /> Saída venda</button>
                        {podeAjustar && <button disabled={!online} onClick={() => { setMenu(null); onAjuste(r.id); }}><EIcon name="sliders" size={16} /> Ajustar</button>}
                      </div>
                    )}
                  </td>
                </tr>
              );
            })}
            {!rows.length && (
              <tr className="empty-row"><td colSpan="14">Nenhum pallet com esses filtros. <button className="link-btn" onClick={() => setSt(Object.assign({}, st, { busca: '', gal: 'todos', cat: 'todos', pontas: false, rascunho: false, validade: 'todos' }))}>Limpar filtros</button></td></tr>
            )}
          </tbody>
        </table>
      </div>

      {/* Rodapé de totais */}
      <div className="tab-rodape">
        <span className="rod-item"><strong>{rows.length}</strong> {rows.length === 1 ? 'pallet' : 'pallets'}</span>
        <span className="rod-sep">·</span>
        <span className="rod-item"><strong>{totCx}</strong> caixas</span>
        {totSacos > 0 && <React.Fragment><span className="rod-sep">·</span><span className="rod-item"><strong>{totSacos}</strong> sacos</span></React.Fragment>}
        <span className="rod-sep">·</span>
        <span className="rod-item"><strong>{ESTQ.fmtNum(totM2)}</strong> m²</span>
      </div>
    </div>
  );
}

function FiltroSelect({ label, value, onChange, opcoes }) {
  return (
    <label className="tf-select">
      <span>{label}</span>
      <select value={value} onChange={(e) => onChange(e.target.value)}>
        {opcoes.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
      </select>
    </label>
  );
}

/* ===== Movimentações ===== */
function buildMovs(db) {
  const list = [];
  Object.keys(db.movs).forEach((pid) => {
    const pal = db.pallets[pid];
    if (!pal) return;
    const prod = ESTQ.PRODUTOS[pal.prod] || db.produtos[pal.prod];
    db.movs[pid].forEach((m, i) => {
      list.push(Object.assign({ pid, pal, prod, _ord: parseData(m.quando, m.hora), _k: pid + i }, m));
    });
  });
  return list;
}

const TIPO_LABEL = { entrada: 'Entrada', movimentacao: 'Movimentação', saida_venda: 'Saída venda', ajuste: 'Ajuste', marcacao_ponta: 'Ponta' };

function Movimentacoes({ db, st, setSt, onLinha }) {
  let list = buildMovs(db);
  const q = st.busca.trim().toLowerCase();
  const vq = st.venda.trim();
  list = list.filter((m) => {
    if (st.tipo !== 'todos' && m.tipo !== st.tipo) return false;
    if (st.operador !== 'todos' && m.quem !== st.operador) return false;
    if (vq && !(m.tipo === 'saida_venda' && String(m.venda).includes(vq))) return false;
    if (q && !((m.prod.nome + ' ' + (m.pal.lote || '')).toLowerCase().includes(q))) return false;
    return true;
  });
  const dir = st.sortDir === 'asc' ? 1 : -1;
  list.sort((a, b) => (a._ord - b._ord) * dir);

  const operadores = Array.from(new Set(buildMovs(db).map((m) => m.quem)));

  return (
    <div className="tab-conteudo">
      <div className="tab-filtros">
        <div className="tf-busca venda">
          <EIcon name="truck" size={18} />
          <input value={st.venda} onChange={(e) => setSt(Object.assign({}, st, { venda: e.target.value }))} placeholder="Buscar nº de venda (ex.: 4582)" inputMode="numeric" />
        </div>
        <div className="tf-busca">
          <EIcon name="search" size={18} />
          <input value={st.busca} onChange={(e) => setSt(Object.assign({}, st, { busca: e.target.value }))} placeholder="Produto ou lote…" />
        </div>
        <FiltroSelect label="Tipo" value={st.tipo} onChange={(v) => setSt(Object.assign({}, st, { tipo: v }))}
          opcoes={[['todos', 'Todos'], ['entrada', 'Entrada'], ['movimentacao', 'Movimentação'], ['saida_venda', 'Saída venda'], ['ajuste', 'Ajuste'], ['marcacao_ponta', 'Ponta']]} />
        <FiltroSelect label="Operador" value={st.operador} onChange={(v) => setSt(Object.assign({}, st, { operador: v }))}
          opcoes={[['todos', 'Todos']].concat(operadores.map((o) => [o, o.split(' ')[0]]))} />
        <span className="mov-leitura"><EIcon name="lock" size={15} /> Somente leitura</span>
      </div>

      <div className="tab-scroll">
        <table className="tbl">
          <thead>
            <tr>
              <th className="active" onClick={() => setSt(Object.assign({}, st, { sortDir: st.sortDir === 'asc' ? 'desc' : 'asc' }))}>
                <span className="th-in">Data/hora <EIcon name="arrowUpDown" size={13} /></span>
              </th>
              <th>Tipo</th><th>Produto</th><th>Lote</th><th className="num">Qtd</th>
              <th>Nº venda</th><th>De → Para</th><th>Operador</th>
            </tr>
          </thead>
          <tbody>
            {list.map((m) => (
              <tr key={m._k} onClick={() => onLinha(m.pid)}>
                <td className="data-cell">{m.quando}{m.hora ? ' · ' + m.hora : ''}</td>
                <td><span className={'mov-tag ' + m.tipo}>{TIPO_LABEL[m.tipo]}</span></td>
                <td><span className="prod-cell">{m.prod.foto ? <img className="prod-sw foto" src={m.prod.foto} alt="" /> : <span className="prod-sw" style={{ background: m.prod.cor }}></span>}{m.prod.curto}</span></td>
                <td>{m.pal.lote || '—'}</td>
                <td className="num">{m.cx != null ? m.cx : (m.delta != null ? (m.delta > 0 ? '+' + m.delta : m.delta) : '—')}</td>
                <td>{m.venda ? <span className="venda-num">{m.venda}</span> : '—'}</td>
                <td>{m.de ? m.de + ' → ' + m.para : '—'}</td>
                <td>{m.quem}</td>
              </tr>
            ))}
            {!list.length && (
              <tr className="empty-row"><td colSpan="8">Nenhuma movimentação encontrada{vq ? ' para a venda ' + vq : ''}.</td></tr>
            )}
          </tbody>
        </table>
      </div>
      <div className="tab-rodape"><span className="rod-item"><strong>{list.length}</strong> {list.length === 1 ? 'movimentação' : 'movimentações'}</span></div>
    </div>
  );
}

/* ===== Por marca (consolidação por marca → produtos) ===== */
function PorMarca({ db, st, setSt, onLinha }) {
  const { useState } = React;
  const [abertas, setAbertas] = useState(() => ({}));
  const [prodAberto, setProdAberto] = useState(null);

  // monta: marca → { produtos: [{prod, pallets[], totalCx, totalM2, nPallets, ponta, vencido}] }
  const porMarca = {};
  Object.values(db.pallets).forEach((pal) => {
    if (pal.arquivado) return;
    const pos = ESTQ.findPos(db, pal.id);
    if (!pos) return;
    if (st.gal !== 'todos' && String(pos.gal) !== st.gal) return;
    const prod = ESTQ.PRODUTOS[pal.prod] || db.produtos[pal.prod];
    if (st.cat !== 'todos' && prod.cat !== st.cat) return;
    if (st.validade !== 'todos') {
      const e = ESTQ.isMat(pal) ? ESTQ.validadeEstado(pal.validade) : null;
      if (st.validade === 'vencidos' && !(e && e.st === 'vencido')) return;
      if (st.validade === 'proximos' && !(e && e.st === 'breve')) return;
    }
    const marca = prod.marca || '—';
    const m = porMarca[marca] || (porMarca[marca] = { marca, produtos: {} });
    const pp = m.produtos[prod.id] || (m.produtos[prod.id] = { prod, pallets: [], cx: 0, m2: 0, ponta: 0, vencido: 0, breve: 0 });
    pp.pallets.push({ pal, pos });
    pp.cx += pal.cx;
    pp.m2 += ESTQ.palletM2Num(pal);
    if (pal.status === 'ponta' || pal.status === 'ponta_sugerida') pp.ponta++;
    const ve = ESTQ.isMat(pal) ? ESTQ.validadeEstado(pal.validade) : null;
    if (ve && ve.st === 'vencido') pp.vencido++;
    if (ve && ve.st === 'breve') pp.breve++;
  });

  const marcas = Object.values(porMarca).map((m) => {
    const prods = Object.values(m.produtos).sort((a, b) => a.prod.nome.localeCompare(b.prod.nome));
    const agg = prods.reduce((s, p) => {
      s.cxPiso += p.prod.cat === 'material' ? 0 : p.cx;
      s.sacos += p.prod.cat === 'material' ? p.cx : 0;
      s.ponta += p.ponta; s.vencido += p.vencido; s.breve += p.breve;
      return s;
    }, { cxPiso: 0, sacos: 0, ponta: 0, vencido: 0, breve: 0 });
    return { marca: m.marca, prods, agg };
  }).sort((a, b) => a.marca.localeCompare(b.marca));

  function toggle(marca) { setAbertas((a) => Object.assign({}, a, { [marca]: !a[marca] })); }

  return (
    <div className="tab-conteudo">
      <div className="tab-filtros">
        <span className="marca-titulo">Estoque consolidado por marca</span>
        <FiltroSelect label="Galpão" value={st.gal} onChange={(v) => setSt(Object.assign({}, st, { gal: v }))}
          opcoes={[['todos', 'Todos'], ['1', 'G1'], ['2', 'G2'], ['3', 'G3']]} />
        <FiltroSelect label="Categoria" value={st.cat} onChange={(v) => setSt(Object.assign({}, st, { cat: v }))}
          opcoes={[['todos', 'Todas'], ['piso', 'Piso'], ['material', 'Material']]} />
        <FiltroSelect label="Validade" value={st.validade} onChange={(v) => setSt(Object.assign({}, st, { validade: v }))}
          opcoes={[['todos', 'Todas'], ['vencidos', 'Vencidos'], ['proximos', 'Próx. 30 dias']]} />
        <span className="mov-leitura"><EIcon name="lock" size={15} /> Somente leitura</span>
      </div>

      <div className="tab-scroll marca-scroll">
        {marcas.map(({ marca, prods, agg }) => {
          const open = !!abertas[marca];
          const resumo = [];
          resumo.push(prods.length + (prods.length === 1 ? ' produto' : ' produtos'));
          if (agg.cxPiso) resumo.push(agg.cxPiso + ' cx');
          if (agg.sacos) resumo.push(agg.sacos + ' sacos');
          return (
            <div className={'marca-sec' + (open ? ' open' : '')} key={marca}>
              <button className="marca-head" onClick={() => toggle(marca)}>
                <EIcon name="chevR" size={20} style={{ transform: open ? 'rotate(90deg)' : 'none', transition: 'transform 150ms', color: 'var(--gray-500)' }} />
                <span className="marca-nome">{marca}</span>
                <span className="marca-resumo">{resumo.join(' · ')}</span>
                <span className="marca-selos">
                  {agg.ponta > 0 && <span className="mini-selo ponta">{agg.ponta} em ponta</span>}
                  {agg.breve > 0 && <span className="mini-selo breve">{agg.breve} vence breve</span>}
                  {agg.vencido > 0 && <span className="mini-selo venc">{agg.vencido} vencido</span>}
                </span>
              </button>

              {open && (
                <div className="marca-prods">
                  {prods.map((p) => {
                    const isMat = p.prod.cat === 'material';
                    const expandido = prodAberto === p.prod.id;
                    return (
                      <div className="marca-prod-wrap" key={p.prod.id}>
                        <button className={'marca-prod' + (expandido ? ' on' : '')} onClick={() => setProdAberto(expandido ? null : p.prod.id)}>
                          <span className="mp-sw" style={{ background: p.prod.cor }}></span>
                          <span className="mp-nome">{p.prod.nome}</span>
                          <span className="mp-cod">{p.prod.codigo ? 'Cód ' + p.prod.codigo : ''}</span>
                          <span className={'cat-tag ' + p.prod.cat}>{isMat ? 'Material' : 'Piso'}</span>
                          <span className="mp-tot">{p.cx} {isMat ? 'sacos' : 'cx'}{!isMat ? ' · ' + ESTQ.fmtNum(p.m2) + ' m²' : ''}</span>
                          <span className="mp-pallets">{p.pallets.length} {p.pallets.length === 1 ? 'pallet' : 'pallets'}</span>
                          <span className="mp-selos">
                            {p.ponta > 0 && <span className="mini-selo ponta">ponta</span>}
                            {p.breve > 0 && <span className="mini-selo breve">vence</span>}
                            {p.vencido > 0 && <span className="mini-selo venc">vencido</span>}
                          </span>
                          <EIcon name="chevR" size={17} style={{ transform: expandido ? 'rotate(90deg)' : 'none', color: 'var(--gray-400)' }} />
                        </button>
                        {expandido && (
                          <div className="mp-lista">
                            {p.pallets.map(({ pal, pos }) => {
                              const ve = isMat ? ESTQ.validadeEstado(pal.validade) : null;
                              return (
                                <button className="mp-pallet" key={pal.id} onClick={() => onLinha(pal.id)}>
                                  <span className="mpp-pos">{pos.rascunho ? 'Rascunho G' + pos.gal : pos.code + ' · N' + pos.nivel}</span>
                                  <span className="mpp-q">{ESTQ.qtdCurto(pal)}</span>
                                  {pal.lote && <span className="mpp-lote">Lote {pal.lote}</span>}
                                  {pal.status === 'ponta_sugerida' && <span className="tpill sug">PONTA?</span>}
                                  {pal.status === 'ponta' && <span className="tpill ponta">PONTA</span>}
                                  {ve && ve.st === 'vencido' && <span className="tpill venc">Vencido</span>}
                                  {ve && ve.st === 'breve' && <span className="tpill breve">Vence breve</span>}
                                  <EIcon name="chevR" size={16} style={{ marginLeft: 'auto', color: 'var(--gray-400)' }} />
                                </button>
                              );
                            })}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })}
        {!marcas.length && <div className="rasc-empty" style={{ padding: 60 }}><div className="t">Nenhuma marca com esses filtros</div></div>}
      </div>
      <div className="tab-rodape"><span className="rod-item"><strong>{marcas.length}</strong> {marcas.length === 1 ? 'marca' : 'marcas'}</span></div>
    </div>
  );
}

/* ===== Vista Tabela (container com abas) ===== */
function TabelaView({ db, papel, online, filtroVenda, onLinha, onSaida, onAjuste }) {
  const { useState } = React;
  const [aba, setAba] = useState(filtroVenda ? 'movimentacoes' : TAB_STATE.aba);
  const [estSt, setEstStRaw] = useState(TAB_STATE.est);
  const [movSt, setMovStRaw] = useState(() => filtroVenda ? Object.assign({}, TAB_STATE.mov, { venda: filtroVenda }) : TAB_STATE.mov);
  const [marcaSt, setMarcaStRaw] = useState(TAB_STATE.marca || { gal: 'todos', cat: 'todos', validade: 'todos' });
  const setEstSt = (v) => { TAB_STATE.est = v; setEstStRaw(v); };
  const setMovSt = (v) => { TAB_STATE.mov = v; setMovStRaw(v); };
  const setMarcaSt = (v) => { TAB_STATE.marca = v; setMarcaStRaw(v); };
  const setAbaP = (a) => { TAB_STATE.aba = a; setAba(a); };

  return (
    <div className="tabela-view" data-screen-label="Tabela">
      <div className="tab-abas">
        <button className={'tab-aba' + (aba === 'estoque' ? ' on' : '')} onClick={() => setAbaP('estoque')}>
          <EIcon name="table" size={19} /> Estoque atual
        </button>
        <button className={'tab-aba' + (aba === 'movimentacoes' ? ' on' : '')} onClick={() => setAbaP('movimentacoes')}>
          <EIcon name="clock" size={19} /> Movimentações
        </button>
        <button className={'tab-aba' + (aba === 'marca' ? ' on' : '')} onClick={() => setAbaP('marca')}>
          <EIcon name="layers" size={19} /> Por marca
        </button>
      </div>
      {aba === 'estoque' && <EstoqueAtual db={db} papel={papel} online={online} st={estSt} setSt={setEstSt} onLinha={onLinha} onSaida={onSaida} onAjuste={onAjuste} />}
      {aba === 'movimentacoes' && <Movimentacoes db={db} st={movSt} setSt={setMovSt} onLinha={onLinha} />}
      {aba === 'marca' && <PorMarca db={db} st={marcaSt} setSt={setMarcaSt} onLinha={onLinha} />}
    </div>
  );
}

/* ===== Sheet de Ajuste (gestor/escritório) ===== */
const MOTIVOS = ['Quebra', 'Contagem', 'Avaria', 'Sobra'];

/* Ajuste — sheet multi-step: PIN → quantidade → observação → resumo.
   PIN identifica a pessoa; permissão é do papel dela (gestor/escritório). */
function AjusteSheet({ db, palletId, online, sessaoInicial, onAutenticado, onConfirm, onClose }) {
  const { useState } = React;
  const pal = db.pallets[palletId];
  const prod = ESTQ.PRODUTOS[pal.prod] || db.produtos[pal.prod];
  const isMat = prod.cat === 'material';
  const pos = ESTQ.findPos(db, palletId);
  const posLabel = pos ? (pos.rascunho ? 'Rascunho do G' + pos.gal : pos.code + ' · N' + pos.nivel) : '—';

  const [passo, setPasso] = useState(sessaoInicial ? 2 : 1);     // 1 PIN · 2 qtd · 3 obs · 4 resumo
  const [operador, setOperador] = useState(sessaoInicial ? sessaoInicial.operador : null);
  const [pin, setPin] = useState(sessaoInicial ? sessaoInicial.pin : null);
  const [nova, setNova] = useState(String(pal.cx));
  const [obs, setObs] = useState('');
  const [motivoTag, setMotivoTag] = useState(null);
  const [erro, setErro] = useState(false);
  const [erroServidor, setErroServidor] = useState(null);
  const [enviando, setEnviando] = useState(false);

  const n = parseInt(nova || '0', 10);
  const delta = n - pal.cx;
  const unid = isMat ? prod.un[1] : 'caixas';
  const obsOk = obs.trim().length >= 3;

  function pinOk(op, p) { setOperador(op); setPin(p); onAutenticado && onAutenticado(op, p); setPasso(2); }
  function aplicarChip(m) {
    setMotivoTag(m);
    setObs((prev) => {
      const base = prev.trim();
      if (!base) return m;
      // se o texto era exatamente outro chip, troca; senão prefixa
      if (MOTIVOS.includes(base)) return m;
      return base;
    });
  }
  function confirmar() {
    if (!online) { setErro(true); return; }
    setErroServidor(null); setEnviando(true);
    const obsFinal = (motivoTag && obs.trim() !== motivoTag ? motivoTag + ' — ' : '') + obs.trim();
    onConfirm({ operador, pin, nova: n, delta, obs: obsFinal, motivoTag })
      .catch((e) => { setEnviando(false); setErroServidor(e.message); });
    // sucesso: o pai fecha o sheet (onConfirm resolve e limpa `ajuste` no app.jsx)
  }

  function diffPill(extra) {
    return (
      <span className={'ac-delta inline' + (delta < 0 ? ' neg' : delta > 0 ? ' pos' : '') + (extra || '')}>
        {delta === 0 ? 'sem diferença' : (delta > 0 ? '+' + delta : delta) + ' ' + unid}
        {!isMat && delta !== 0 ? ' · ' + (delta > 0 ? '+' : '−') + ESTQ.fmtNum(Math.abs(delta) * prod.m2cx) + ' m²' : ''}
      </span>
    );
  }

  return (
    <div className="scrim center" onClick={onClose}>
      <div className="ajuste-sheet" data-screen-label={'Ajuste ' + passo + '/4'} onClick={(e) => e.stopPropagation()}>
        <div className="np-head">
          <div>
            <h2>Ajustar contagem</h2>
            <div className="aj-sub">{prod.nome}{pal.lote ? ' · Lote ' + pal.lote : ''} · {posLabel}</div>
          </div>
          <div className="aj-prog">
            {[1, 2, 3, 4].map((i) => <span key={i} className={'wz-seg' + (i <= passo ? ' on' : '')}></span>)}
          </div>
          <button className="btn-fechar-sheet" onClick={onClose}><EIcon name="x" size={19} /> Fechar</button>
        </div>

        {/* 1 · PIN */}
        {passo === 1 && (
          <div className="ajuste-body pin">
            <div className="ajuste-resumo-pin">Quem está ajustando o estoque?</div>
            <PinPad onValidado={pinOk}
              permite={(op) => op.papel === 'gestor' || op.papel === 'escritorio'}
              acaoLabel="ajustar o estoque" operadores={db.operadores} />
          </div>
        )}

        {/* 2 · Quantidade */}
        {passo === 2 && (
          <div className="ajuste-body">
            <div className="ajuste-conta">
              <div className="ac-bloco">
                <span className="ac-lbl">Quantidade atual</span>
                <span className="ac-val atual">{pal.cx}</span>
                <span className="ac-un">{unid}</span>
              </div>
              <EIcon name="arrowRight" size={26} style={{ color: 'var(--gray-400)' }} />
              <div className="ac-bloco">
                <span className="ac-lbl">Nova contagem</span>
                <input className="ac-input" value={nova} inputMode="numeric" autoFocus
                  onChange={(e) => setNova(e.target.value.replace(/\D/g, ''))} />
                <span className="ac-un">{unid}</span>
              </div>
              <div className={'ac-delta' + (delta < 0 ? ' neg' : delta > 0 ? ' pos' : '')}>
                {delta === 0 ? 'sem diferença' : (delta > 0 ? '+' + delta : delta) + ' ' + unid}
                {!isMat && delta !== 0 ? ' · ' + (delta > 0 ? '+' : '−') + ESTQ.fmtNum(Math.abs(delta) * prod.m2cx) + ' m²' : ''}
              </div>
            </div>
            <div className="np-foot">
              <button className="btn-cancelar" onClick={onClose}>Cancelar</button>
              <button className="btn-wz-confirmar np-salvar" disabled={delta === 0} onClick={() => setPasso(3)}>
                Continuar <EIcon name="arrowRight" size={20} />
              </button>
            </div>
          </div>
        )}

        {/* 3 · Observação obrigatória + chips */}
        {passo === 3 && (
          <div className="ajuste-body">
            <div className="aj-diff-row">{diffPill()}</div>
            <div className="ajuste-campo">
              <label>Motivo do ajuste <span className="obrig">obrigatório</span></label>
              <div className="motivo-chips">
                {MOTIVOS.map((m) => (
                  <button key={m} type="button" className={'chip-rec' + (motivoTag === m ? ' on' : '')} onClick={() => aplicarChip(m)}>{m}</button>
                ))}
              </div>
              <textarea value={obs} autoFocus rows="3"
                onChange={(e) => { setObs(e.target.value); if (motivoTag && e.target.value.trim() !== motivoTag) setMotivoTag(null); }}
                placeholder="Ex.: recontagem física — 3 caixas avariadas removidas"></textarea>
              {!obsOk && <span className="campo-erro">Descreva o motivo para registrar o ajuste</span>}
            </div>
            <div className="np-foot">
              <button className="btn-cancelar" onClick={() => setPasso(2)}>Voltar</button>
              <button className="btn-wz-confirmar np-salvar" disabled={!obsOk} onClick={() => setPasso(4)}>
                Continuar <EIcon name="arrowRight" size={20} />
              </button>
            </div>
          </div>
        )}

        {/* 4 · Resumo */}
        {passo === 4 && (
          <div className="ajuste-body">
            <div className="resumo-card" style={{ margin: '0 24px' }}>
              <div className="ajuste-prod" style={{ marginBottom: 14 }}>
                <Foto prod={prod} />
                <div className="info">
                  <div className="prod-nome">{prod.nome}</div>
                  <div className="prod-marca">{prod.marca}{pal.lote ? ' · Lote ' + pal.lote : ''} · {posLabel}</div>
                </div>
              </div>
              <div className="resumo-grid">
                <div className="rg-item"><span className="rg-lbl">De → Para</span><span className="rg-val">{pal.cx} → {n} {unid}</span></div>
                <div className="rg-item"><span className="rg-lbl">Diferença</span><span className="rg-val">{diffPill()}</span></div>
                <div className="rg-item"><span className="rg-lbl">Motivo</span><span className="rg-val rg-motivo">{motivoTag && obs.trim() !== motivoTag ? motivoTag + ' — ' : ''}{obs.trim()}</span></div>
                <div className="rg-item"><span className="rg-lbl">Operador</span><span className="rg-val">{operador.nome.split(' ')[0]}</span></div>
              </div>
              {n <= 0 && <div className="aviso-resumo navy"><EIcon name="inbox" size={18} /> A contagem zera o pallet — ele será removido do mapa e {posLabel} ficará livre</div>}
              {erro && <div className="aviso-resumo erro"><EIcon name="wifiOff" size={18} /> Sem internet — o ajuste não foi registrado. Tente de novo quando voltar a conexão.</div>}
              {erroServidor && <div className="aviso-resumo erro"><EIcon name="alert" size={18} /> Não foi possível registrar: {erroServidor}</div>}
            </div>
            <div className="np-foot">
              <button className="btn-cancelar" onClick={() => setPasso(3)}>Voltar</button>
              <button className="btn-wz-confirmar np-salvar saida" disabled={enviando} onClick={confirmar}>
                <EIcon name="check" size={20} /> {enviando ? 'Registrando…' : 'Confirmar ajuste'}
              </button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { TabelaView, AjusteSheet, StatusPill });
