/* global React, Icon, Button, Badge, Card, Drawer, Field, PageHead, SearchableSelect, KPI, brl, fmtDate,
          useMktLojasList, useEmpresasList, useContasList, useProdutosList, usePedidosList,
          useClientesList, useSaloesList, useDistribuidoresList, useFinPeriodo, PeriodoFilter */

// ─── Módulo Marketplace · FASE 1 (cadastro de Lojas) ─────────────────────────
// Lojas próprias em marketplace (ML/Shopee/TikTok). Fase 1 = só o CRUD de lojas.
// O lançamento semanal (pedido marketplace), o repasse+taxa e o dashboard por
// plataforma vêm nas fases seguintes. Ver DESIGN_marketplace.md.

const PLATAFORMAS = ['Mercado Livre', 'Shopee', 'TikTok Shop', 'Outra'];
const BLANK_LOJA = { nome: '', plataforma: 'Mercado Livre', empresa_id: '', conta_id: '', situacao: 'Ativa', observacoes: '' };

function MarketplaceLojas({ onNav }) {   // eslint-disable-line no-unused-vars
  const s = useMktLojasList([]);
  const empresasHook = useEmpresasList([]);
  const contasHook = useContasList([]);
  const [saveErr, setSaveErr] = React.useState('');
  const [mostrarArq, setMostrarArq] = React.useState(false);

  const empresasAtivas = (empresasHook.rows || []).filter(e => e.ativo !== false);
  const contasAtivas = (contasHook.rows || []).filter(c => c.situacao !== 'Arquivada');
  const empresaNome = (id) => { const e = (empresasHook.rows || []).find(x => x.id === id); return e ? (e.nome_fantasia || e.razao_social || e.nome || '—') : '—'; };
  const contaNome = (id) => { const c = (contasHook.rows || []).find(x => x.id === id); return c ? c.nome : '—'; };

  const ordenadas = [...s.rows].sort((a, b) => String(a.nome || '').localeCompare(String(b.nome || '')));
  const visiveis = ordenadas.filter(l => mostrarArq ? true : l.situacao !== 'Arquivada');
  const ativasCount = ordenadas.filter(l => l.situacao !== 'Arquivada').length;
  const arquivadasCount = ordenadas.filter(l => l.situacao === 'Arquivada').length;

  const abrirNovo = () => { setSaveErr(''); s.open('new', null, { ...BLANK_LOJA }); };
  const abrirEdit = (l) => { setSaveErr(''); s.open('edit', s.rows.findIndex(x => x.id === l.id)); };

  const salvar = () => {
    const d = s.edit.draft;
    if (!(d.nome || '').trim()) { setSaveErr('Informe o nome da loja.'); return; }
    if (!d.plataforma) { setSaveErr('Escolha a plataforma.'); return; }
    setSaveErr('');
    s.save();
  };
  const setSituacao = async (l, situacao) => {
    if (!window.tmSupabase || !l.id) return;
    await window.tmSupabase.from('marketplace_lojas').update({ situacao }).eq('id', l.id);
    s.reload();
  };
  const excluir = () => {
    const idx = s.rows.findIndex(x => x.id === s.edit.draft.id);
    if (idx >= 0) s.remove(idx);
  };

  const d = s.edit && s.edit.draft;
  const isNew = s.edit && s.edit.mode === 'new';

  return (
    <div className="canvas">
      <PageHead title="Marketplace · Lojas"
        sub={s.rows.length > 0
          ? `${ativasCount} loja${ativasCount !== 1 ? 's' : ''} ativa${ativasCount !== 1 ? 's' : ''}${arquivadasCount ? ` · ${arquivadasCount} arquivada${arquivadasCount !== 1 ? 's' : ''}` : ''}`
          : 'Nenhuma loja cadastrada'}
        right={<Button variant="primary" icon="plus" size="sm" onClick={abrirNovo}>Nova loja</Button>} />

      <Card>
        {arquivadasCount > 0 && (
          <div style={{ display: 'flex', justifyContent: 'flex-end', padding: '10px 14px', borderBottom: '1px solid var(--tm-line-1)' }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12.5, color: 'var(--tm-fg-3)', cursor: 'pointer' }}>
              <input type="checkbox" checked={mostrarArq} onChange={e => setMostrarArq(e.target.checked)} /> Mostrar arquivadas
            </label>
          </div>
        )}

        {s.rows.length === 0 ? (
          <div style={{ padding: '48px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>
            <Icon name="store" size={36} style={{ opacity: 0.3, marginBottom: 12 }} />
            <div style={{ fontSize: 14, marginBottom: 6 }}>Nenhuma loja de marketplace</div>
            <div style={{ fontSize: 12 }}>Cadastre a loja (ML, Shopee, TikTok…) onde a TopMix vende direto.</div>
          </div>
        ) : (
          <table className="tbl">
            <thead><tr>
              <th>Loja</th><th>Plataforma</th><th>Empresa dona</th><th>Conta do repasse</th><th>Situação</th><th></th>
            </tr></thead>
            <tbody>
              {visiveis.map((l) => {
                const arq = l.situacao === 'Arquivada';
                return (
                  <tr key={l.id} className="clickable" onClick={() => abrirEdit(l)} style={arq ? { opacity: 0.55 } : undefined}>
                    <td style={{ fontWeight: 500 }}>{l.nome}</td>
                    <td><span className="ch-chip">{l.plataforma}</span></td>
                    <td>{l.empresa_id ? empresaNome(l.empresa_id) : <Badge tone="warning">sem empresa</Badge>}</td>
                    <td>{l.conta_id ? contaNome(l.conta_id) : <span className="muted">— defina no repasse</span>}</td>
                    <td><Badge tone={arq ? 'neutral' : 'success'}>{l.situacao || 'Ativa'}</Badge></td>
                    <td onClick={e => e.stopPropagation()} style={{ whiteSpace: 'nowrap' }}>
                      <Button variant="ghost" size="sm" icon="pencil" onClick={() => abrirEdit(l)} />
                      {arq
                        ? <Button variant="secondary" size="sm" icon="archive-restore" onClick={() => setSituacao(l, 'Ativa')}>Desarquivar</Button>
                        : <Button variant="secondary" size="sm" icon="archive" onClick={() => setSituacao(l, 'Arquivada')}>Arquivar</Button>}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Card>

      {s.edit && (
        <Drawer open={true} width={520} title={isNew ? 'Nova loja de marketplace' : 'Editar loja'}
          onClose={s.close}
          footer={<>
            {!isNew && <Button variant="danger-ghost" size="sm" icon="trash-2" onClick={excluir}>Excluir</Button>}
            <span style={{ flex: 1 }} />
            <Button variant="secondary" size="sm" onClick={s.close}>Cancelar</Button>
            <Button variant="primary" size="sm" icon="check" onClick={salvar}>Salvar</Button>
          </>}>

          {saveErr && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14, padding: '10px 12px',
              borderRadius: 'var(--tm-radius-sm)', fontSize: 12.5, color: 'var(--tm-danger)',
              background: 'color-mix(in srgb, var(--tm-danger) 12%, transparent)', border: '1px solid color-mix(in srgb, var(--tm-danger) 30%, transparent)' }}>
              <Icon name="alert-circle" size={15} /> <span>{saveErr}</span>
            </div>
          )}

          <Field label="Nome da loja *">
            <input className="input" value={d.nome || ''} placeholder="Ex.: TopMix Oficial · ML" onChange={e => s.set('nome', e.target.value)} />
          </Field>

          <div className="field-grid-2">
            <Field label="Plataforma *">
              <select className="input" value={d.plataforma || 'Mercado Livre'} onChange={e => s.set('plataforma', e.target.value)}>
                {PLATAFORMAS.map(p => <option key={p} value={p}>{p}</option>)}
              </select>
            </Field>
            <Field label="Empresa dona">
              <select className="input" value={d.empresa_id || ''} onChange={e => s.set('empresa_id', e.target.value)}>
                <option value="">Selecionar…</option>
                {empresasAtivas.map(e => <option key={e.id} value={e.id}>{e.nome_fantasia || e.razao_social || e.nome}</option>)}
                {d.empresa_id && !empresasAtivas.some(e => e.id === d.empresa_id) && <option value={d.empresa_id}>{empresaNome(d.empresa_id)}</option>}
              </select>
            </Field>
          </div>

          <Field label="Conta do repasse (banco onde o PIX cai)" hint="Onde o marketplace deposita o líquido. Pode definir depois, no repasse.">
            <select className="input" value={d.conta_id || ''} onChange={e => s.set('conta_id', e.target.value)}>
              <option value="">Selecionar…</option>
              {contasAtivas.map(c => <option key={c.id} value={c.id}>{c.nome}</option>)}
              {d.conta_id && !contasAtivas.some(c => c.id === d.conta_id) && <option value={d.conta_id}>{contaNome(d.conta_id)}</option>}
            </select>
          </Field>

          <Field label="Observações">
            <textarea className="input" rows={2} value={d.observacoes || ''} onChange={e => s.set('observacoes', e.target.value)} />
          </Field>
        </Drawer>
      )}
    </div>
  );
}

// ─── FASE 2 — Lançamento semanal ─────────────────────────────────────────────
// Um lançamento vira um PEDIDO marcado (marketplace_loja_id, numero MKT-…, origem
// 'manual', cliente_nome = nome da loja, status Atendido). Reusa a mecânica do
// pedido: salvarPedido faz o snapshot de custo (preco_custo); baixamos estoque via
// salvarMovimentacao (Saída); e criamos 1 recebível CHEIO "Em aberto" (a venda
// bruta). O repasse+taxa é a Fase 3.
const ABBR_PLAT = { 'Mercado Livre': 'ML', 'Shopee': 'SH', 'TikTok Shop': 'TT' };
function gerarNumMkt(loja, periodoFimIso) {
  const abbr = ABBR_PLAT[loja && loja.plataforma] || 'MK';
  const p2 = (n) => String(n).padStart(2, '0');
  const d = periodoFimIso ? new Date(periodoFimIso + 'T12:00:00') : new Date();
  const yymmdd = String(d.getFullYear()).slice(2) + p2(d.getMonth() + 1) + p2(d.getDate());
  const now = new Date();
  return `MKT-${yymmdd}-${abbr}${p2(now.getHours())}${p2(now.getMinutes())}`;
}

// Cria o lançamento (pedido marketplace + estoque + recebível). Retorna {pedido} ou {error}.
async function salvarLancamento(loja, periodoInicio, periodoFim, linhas) {
  const itens = linhas
    .filter(l => l.produtoId && Number(l.qty) > 0)
    .map(l => ({ sku: l.sku, desc: l.desc, un: 'UN', qty: Number(l.qty), precoLista: Number(l.preco) || 0, descPct: 0,
      produtoId: l.produtoId, variacaoId: l.variacaoId || null,
      visitas: l.visitas, qtdVendas: l.qtdVendas, conversao: l.conversao }));
  if (!itens.length) return { error: { message: 'Adicione ao menos um produto com quantidade.' } };

  const num = gerarNumMkt(loja, periodoFim);
  const draft = {
    num, cli: loja.nome, cliId: null, canal: 'Marketplace',
    marketplaceLojaId: loja.id, origem: 'manual',
    status: 'Atendido', dataVenda: fmtDate(periodoFim) || undefined,
    periodoInicio: periodoInicio || null, periodoFim: periodoFim || null,
    pgto: 'Marketplace', items: itens,
  };
  const res = await window.tmDb.salvarPedido(draft);
  if (res.error || !res.pedido) return { error: res.error || { message: 'Falha ao salvar o lançamento.' } };
  const pedido = res.pedido;

  // Baixa estoque (Saída) por item — mesma mecânica do módulo Estoque.
  for (const it of itens) {
    try {
      await window.tmDb.salvarMovimentacao({
        tipo: 'Saída', motivo: 'Venda marketplace', sku: it.sku, produtoId: it.produtoId, variacaoId: it.variacaoId,
        qty: -Math.abs(Number(it.qty) || 0), who: 'Marketplace', nf: num, pedido_ref: num,
      }, true);
    } catch (e) { /* não bloqueia o lançamento; estoque negativo é clampeado em 0 */ }
  }

  // 1 recebível CHEIO "Em aberto" = a venda bruta (o repasse/taxa é a Fase 3).
  // Referência LEGÍVEL (a Naii lê no financeiro); o número MKT fica no pedido_ref/pedido.
  const total = Number(pedido.total) || 0;
  const { error: crErr } = await window.tmSupabase.from('contas_receber').insert({
    referencia: refLegivel(loja, periodoInicio, periodoFim), cliente_nome: loja.nome, pedido_ref: num, pedido_id: pedido.id,
    vencimento: periodoFim || null, parcela: '1/1', valor: total, valor_recebido: 0, status: 'Em aberto',
    forma_pagamento: 'Marketplace', conta_bancaria: null, conta_id: loja.conta_id || null,
    total_parcelas: 1, numero_parcela: 1,
  });
  if (crErr) return { pedido, error: { message: 'Pedido criado, mas o recebível falhou: ' + (crErr.message || crErr.code) } };
  return { pedido };
}

// Rótulo de período: "11–17/08" (mesmo mês) ou "28/07–03/08".
function periodoLabel(iniIso, fimIso) {
  const d = (iso) => { const m = String(iso || '').match(/^(\d{4})-(\d{2})-(\d{2})/); return m ? { d: m[3], mo: m[2] } : null; };
  const a = d(iniIso), b = d(fimIso);
  if (a && b) return a.mo === b.mo ? `${a.d}–${b.d}/${b.mo}` : `${a.d}/${a.mo}–${b.d}/${b.mo}`;
  if (b) return `${b.d}/${b.mo}`;
  return '';
}
// Referência legível do recebível: "Mercado Livre · NG Outlet · 11–17/08".
function refLegivel(loja, iniIso, fimIso) {
  const per = periodoLabel(iniIso, fimIso);
  return `${loja.plataforma} · ${loja.nome}${per ? ' · ' + per : ''}`;
}
// Chave pra casar itens entre versões (variação > produto > sku).
function itemKey(x) { return String(x.variacaoId || x.variacao_id || x.produtoId || x.produto_id || x.sku || ''); }
// Um recebível está "recebido" (repasse registrado) se tem valor_recebido ou status Recebido/Parcial.
function recebimentosDe(recebiveis) { return (recebiveis || []).filter(r => Number(r.valor_recebido) > 0 || r.status === 'Recebido' || r.status === 'Parcial'); }
// Movimento de estoque (qty com SINAL: + entrada, − saída). Reusa salvarMovimentacao.
async function movEstoque(tipo, motivo, item, qtySigned, num) {
  await window.tmDb.salvarMovimentacao({
    tipo, motivo, sku: item.sku, produtoId: item.produtoId || item.produto_id, variacaoId: item.variacaoId || item.variacao_id || null,
    qty: qtySigned, who: 'Marketplace', nf: num, pedido_ref: num,
  }, true);
}

// EDITAR (antes do repasse): ajusta estoque pela DIFERENÇA (compensação, não estorno total)
// e ressincroniza o recebível ABERTO. Trava (recebido) é checada na UI antes de chamar.
async function editarLancamento(pedido, loja, ini, fim, novasLinhas, itensAntigos) {
  const itens = novasLinhas.filter(l => l.produtoId && Number(l.qty) > 0)
    .map(l => ({ sku: l.sku, desc: l.desc, un: 'UN', qty: Number(l.qty), precoLista: Number(l.preco) || 0, descPct: 0,
      produtoId: l.produtoId, variacaoId: l.variacaoId || null, precoCusto: l.precoCusto != null ? l.precoCusto : null,
      visitas: l.visitas, qtdVendas: l.qtdVendas, conversao: l.conversao }));
  if (!itens.length) return { error: { message: 'Adicione ao menos um produto com quantidade.' } };
  const num = pedido.num || pedido.numero;

  const draft = { id: pedido.id, num, cli: loja.nome, canal: 'Marketplace', marketplaceLojaId: loja.id, origem: 'manual',
    status: 'Atendido', dataVenda: fmtDate(fim) || undefined, periodoInicio: ini, periodoFim: fim, pgto: 'Marketplace', items: itens };
  const res = await window.tmDb.salvarPedido(draft);
  if (res.error || !res.pedido) return { error: res.error || { message: 'Falha ao salvar a edição.' } };

  // Estoque por DIFERENÇA: delta = old − new (>0 devolve/Entrada; <0 tira mais/Saída).
  const oldMap = {}, newMap = {}, refItem = {};
  (itensAntigos || []).forEach(it => { const k = itemKey(it); oldMap[k] = (oldMap[k] || 0) + (Number(it.qty) || 0); refItem[k] = it; });
  itens.forEach(it => { const k = itemKey(it); newMap[k] = (newMap[k] || 0) + (Number(it.qty) || 0); refItem[k] = it; });
  for (const k of new Set([...Object.keys(oldMap), ...Object.keys(newMap)])) {
    const delta = (oldMap[k] || 0) - (newMap[k] || 0);
    if (Math.abs(delta) < 1e-9) continue;
    try { await movEstoque(delta > 0 ? 'Entrada' : 'Saída', 'Ajuste lançamento marketplace', refItem[k], delta, num); } catch (e) { /* clamp em 0 */ }
  }

  // Ressincroniza o recebível ABERTO (single). Recebido é preservado (e a UI já bloqueou edição).
  const novoTotal = Number(res.pedido.total) || 0;
  const { data: crs } = await window.tmSupabase.from('contas_receber').select('id,valor_recebido,status').eq('pedido_id', pedido.id);
  const aberto = (crs || []).find(r => !(Number(r.valor_recebido) > 0 || r.status === 'Recebido' || r.status === 'Parcial'));
  if (aberto) {
    await window.tmSupabase.from('contas_receber').update({ valor: novoTotal, referencia: refLegivel(loja, ini, fim), vencimento: fim || null }).eq('id', aberto.id);
  } else {
    await window.tmSupabase.from('contas_receber').insert({ referencia: refLegivel(loja, ini, fim), cliente_nome: loja.nome, pedido_ref: num, pedido_id: pedido.id,
      vencimento: fim || null, parcela: '1/1', valor: novoTotal, valor_recebido: 0, status: 'Em aberto', forma_pagamento: 'Marketplace', conta_id: loja.conta_id || null, total_parcelas: 1, numero_parcela: 1 });
  }
  return { pedido: res.pedido };
}

// CANCELAR: estorno TOTAL. Estoque INVERSO (Entrada auditável, não deleta o movimento
// original), remove o recebível aberto, pedido → Cancelado. Trava (recebido) na UI.
async function cancelarLancamento(pedido, itens) {
  const num = pedido.num || pedido.numero;
  for (const it of itens) {
    try { await movEstoque('Entrada', 'Cancelamento lançamento marketplace', it, Math.abs(Number(it.qty) || 0), num); } catch (e) { /* ok */ }
  }
  const { data: crs } = await window.tmSupabase.from('contas_receber').select('id,valor_recebido,status').eq('pedido_id', pedido.id);
  const abertoIds = (crs || []).filter(r => !(Number(r.valor_recebido) > 0 || r.status === 'Recebido' || r.status === 'Parcial')).map(r => r.id);
  if (abertoIds.length) await window.tmSupabase.from('contas_receber').delete().in('id', abertoIds);
  await window.tmSupabase.from('pedidos').update({ status: 'Cancelado' }).eq('id', pedido.id);
  return { ok: true };
}

// REGISTRAR REPASSE (Fase 3): a Naii informa o LÍQUIDO (PIX) + data; o banco vem da loja.
//  (1) o recebível CHEIO vira Recebido naquela conta/data → +bruto no banco (valor_recebido = bruto);
//  (2) a diferença (bruto − líquido) vira contas_pagar "Taxa de marketplace", Pago, mesma conta/data,
//      pedido_id do lançamento → −taxa. Saldo do banco = bruto − taxa = líquido (o PIX real).
// Receita segue CHEIA (o recebível Recebido conta pelo valor cheio); a taxa é despesa comercial.
// Borda: líquido > bruto → NÃO cria taxa negativa (a UI barra antes; guarda defensiva aqui).
async function registrarRepasse(pedido, loja, contaId, liquido, dataIso, recAberto) {
  const bruto = Number(recAberto && recAberto.valor) || Number(pedido.total) || 0;
  const liq = Number(liquido) || 0;
  const taxa = Math.round((bruto - liq) * 100) / 100;
  if (taxa < 0) return { error: { message: 'O líquido informado é maior que a venda cheia — isso geraria uma taxa negativa. Confira o valor do repasse.' } };
  if (!recAberto || !recAberto.id) return { error: { message: 'Recebível aberto do lançamento não encontrado.' } };

  // (1) Recebível cheio → Recebido (regime de caixa: eixo data_pagamento, na conta da loja).
  const { error: recErr } = await window.tmSupabase.from('contas_receber').update({
    status: 'Recebido', valor_recebido: bruto, data_pagamento: dataIso || null,
    conta_id: contaId || null, forma_pagamento: 'PIX',
  }).eq('id', recAberto.id);
  if (recErr) return { error: { message: 'Falha ao dar baixa no recebível: ' + (recErr.message || recErr.code) } };

  // (2) Taxa = bruto − líquido → contas_pagar Pago (só se houver taxa; 0 não vira lançamento).
  if (taxa > 0) {
    const { error: pagErr } = await window.tmSupabase.from('contas_pagar').insert({
      referencia: 'Taxa marketplace · ' + refLegivel(loja, pedido.periodo_inicio, pedido.periodo_fim),
      fornecedor: loja.plataforma || 'Marketplace', categoria: 'Taxa de marketplace',
      vencimento: dataIso || null, valor: taxa, valor_pago: taxa, status: 'Pago',
      forma_pagamento: 'PIX', data_pagamento: dataIso || null, conta_id: contaId || null, pedido_id: pedido.id,
    });
    if (pagErr) return { error: { message: 'Recebível baixado, mas a taxa falhou: ' + (pagErr.message || pagErr.code) } };
  }

  // Lembra a conta na loja (a Naii pode ter definido o banco só agora, no repasse).
  if (contaId && contaId !== loja.conta_id) {
    try { await window.tmSupabase.from('marketplace_lojas').update({ conta_id: contaId }).eq('id', loja.id); } catch (e) { /* não bloqueia o repasse */ }
  }
  return { ok: true, bruto, taxa, liquido: liq };
}

// Editor de um lançamento (loja + período + linhas de produto/qtd/preço).
function LancamentoForm({ lojas, produtos, edit, onSaved, onClose }) {
  const ehEdicao = !!edit;
  const hoje = new Date().toISOString().slice(0, 10);
  const seteAtras = new Date(Date.now() - 6 * 86400000).toISOString().slice(0, 10);
  const [lojaId, setLojaId] = React.useState(ehEdicao ? (edit.pedido.marketplace_loja_id || '') : (lojas[0] ? lojas[0].id : ''));
  const [ini, setIni] = React.useState(ehEdicao ? String(edit.pedido.periodo_inicio || '').slice(0, 10) || seteAtras : seteAtras);
  const [fim, setFim] = React.useState(ehEdicao ? String(edit.pedido.periodo_fim || '').slice(0, 10) || hoje : hoje);
  // Padrão = 'bruto' (a Naii digita UNIDADES + VENDAS BRUTAS do relatório; o preço médio é
  // calculado). 'unitario' = alternativa (digita preço unitário; o total é calculado).
  const [modoPreco, setModoPreco] = React.useState('bruto');
  const [linhas, setLinhas] = React.useState(ehEdicao
    ? (edit.itens || []).map(it => ({ produtoId: it.produtoId, sku: it.sku, desc: it.desc, variacaoId: it.variacaoId || null,
        qty: it.qty, preco: it.precoLista, bruto: (Number(it.qty) || 0) * (Number(it.precoLista) || 0), precoCusto: it.precoCusto,
        visitas: it.visitas != null ? it.visitas : '', qtdVendas: it.qtdVendas != null ? it.qtdVendas : '', conversao: it.conversao != null ? it.conversao : '' }))
    : [{ produtoId: '', sku: '', desc: '', variacaoId: null, qty: 1, preco: '', bruto: '', visitas: '', qtdVendas: '', conversao: '' }]);
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');

  const prodOpts = (produtos || []).filter(p => p.tipo !== 'insumo').map(p => ({ value: p.id, label: `${p.sku} · ${p.nome || p.name}` }));
  const prodById = {}; (produtos || []).forEach(p => { prodById[p.id] = p; });
  const loja = lojas.find(l => l.id === lojaId);

  const setLinha = (i, patch) => setLinhas(rows => rows.map((r, idx) => idx === i ? { ...r, ...patch } : r));
  const escolherProduto = (i, produtoId) => {
    const p = prodById[produtoId];
    setLinha(i, { produtoId, sku: p ? p.sku : '', desc: p ? (p.nome || p.name) : '',
      preco: p ? (p.eh_kit ? (p.preco_kit_venda || p.preco_venda || '') : (p.preco_venda || '')) : '' });
  };
  const addLinha = () => setLinhas(rows => [...rows, { produtoId: '', sku: '', desc: '', variacaoId: null, qty: 1, preco: '', bruto: '', visitas: '', qtdVendas: '', conversao: '' }]);
  const rmLinha = (i) => setLinhas(rows => rows.length > 1 ? rows.filter((_, idx) => idx !== i) : rows);

  // Vendas brutas (total) da linha e preço médio derivado (brutas ÷ unidades).
  const brutoDe = (l) => modoPreco === 'bruto' ? (Number(l.bruto) || 0) : (Number(l.qty) || 0) * (Number(l.preco) || 0);
  const medioDe = (l) => { const q = Number(l.qty) || 0; return q > 0 ? brutoDe(l) / q : 0; };
  const total = linhas.reduce((a, l) => a + brutoDe(l), 0);
  const validas = linhas.filter(l => l.produtoId && Number(l.qty) > 0 && brutoDe(l) > 0).length;

  // Conversão DERIVADA (nunca digitada): base ÷ visitas, em %.
  // Denominador = visitas. Numerador = nº de VENDAS (pedidos) quando informado; senão UNIDADES.
  // É a definição dos marketplaces (cada visita que vira pedido). Como um pedido pode levar
  // várias unidades, unidades/visitas superestima — por isso só entra como proxy quando
  // qtd_vendas está em branco. O campo "conversão do relatório" é guardado à parte (a base que
  // o marketplace usa pode diferir); se divergir da derivada, mostramos as duas, sem bloquear.
  const temNum = (x) => x != null && x !== '' && Number(x) >= 0;
  const convDados = (l) => {
    const v = Number(l.visitas) || 0;
    if (!temNum(l.visitas) || v <= 0) return null;
    const usouVendas = temNum(l.qtdVendas);
    const base = usouVendas ? (Number(l.qtdVendas) || 0) : (Number(l.qty) || 0);
    return { pct: (base / v) * 100, base: usouVendas ? 'pedidos' : 'unidades' };
  };
  const fmtPct = (n) => (Number(n) || 0).toFixed(2).replace('.', ',') + '%';

  const salvar = async () => {
    if (!lojaId) { setErr('Escolha a loja.'); return; }
    if (!ini || !fim) { setErr('Informe o período (início e fim).'); return; }
    if (!validas) { setErr('Adicione ao menos um produto com unidades e vendas brutas.'); return; }
    setSaving(true); setErr('');
    // O preço que persiste é o MÉDIO (brutas ÷ unidades) → qty × médio = vendas brutas.
    // O snapshot de custo (produtos.custo × unidades) não muda, então a margem segue correta.
    const linhasFinal = linhas.map(l => ({ produtoId: l.produtoId, sku: l.sku, desc: l.desc, variacaoId: l.variacaoId || null,
      qty: Number(l.qty) || 0, preco: medioDe(l), precoCusto: l.precoCusto,
      visitas: l.visitas, qtdVendas: l.qtdVendas, conversao: l.conversao }));
    const r = ehEdicao
      ? await editarLancamento(edit.pedido, loja, ini, fim, linhasFinal, edit.itens)
      : await salvarLancamento(loja, ini, fim, linhasFinal);
    setSaving(false);
    if (r.error) { setErr(r.error.message || 'Erro ao salvar.'); return; }
    onSaved();
  };

  return (
    <Drawer open={true} width={780} title={ehEdicao ? 'Editar lançamento' : 'Novo lançamento de marketplace'}
      subtitle={ehEdicao ? 'O estoque ajusta pela diferença e o recebível aberto é ressincronizado' : 'Resumo semanal por loja · vira um pedido interno que baixa estoque e gera o recebível'}
      onClose={onClose}
      footer={<>
        <span style={{ flex: 1 }} />
        <Button variant="secondary" size="sm" onClick={onClose}>Cancelar</Button>
        <Button variant="primary" size="sm" icon="check" onClick={salvar} disabled={saving || !validas}>
          {saving ? 'Salvando…' : `${ehEdicao ? 'Salvar' : 'Lançar'} (R$ ${brl(total)})`}
        </Button>
      </>}>

      <div className="field-grid-3">
        <Field label="Loja *">
          <select className="input" value={lojaId} disabled={ehEdicao} onChange={e => setLojaId(e.target.value)}>
            <option value="">Selecionar…</option>
            {lojas.map(l => <option key={l.id} value={l.id}>{l.nome} · {l.plataforma}</option>)}
          </select>
        </Field>
        <Field label="Período — início *"><input className="input" type="date" value={ini} onChange={e => setIni(e.target.value)} /></Field>
        <Field label="Período — fim *"><input className="input" type="date" value={fim} onChange={e => setFim(e.target.value)} /></Field>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '10px 0 8px' }}>
        <div style={{ fontSize: 10.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--tm-fg-4)' }}>
          Produtos vendidos na semana
        </div>
        <div style={{ display: 'flex', gap: 4 }}>
          {[{ id: 'bruto', l: 'Vendas brutas' }, { id: 'unitario', l: 'Preço unitário' }].map(m => (
            <button key={m.id} type="button" onClick={() => setModoPreco(m.id)}
              style={{ padding: '4px 10px', fontSize: 11.5, cursor: 'pointer', borderRadius: 'var(--tm-radius-sm)',
                border: '1px solid ' + (modoPreco === m.id ? 'var(--tm-brand-champagne)' : 'var(--tm-line-2)'),
                background: modoPreco === m.id ? 'color-mix(in srgb, var(--tm-brand-champagne) 14%, transparent)' : 'var(--tm-bg-2)',
                color: modoPreco === m.id ? 'var(--tm-brand-champagne-deep, var(--tm-fg-1))' : 'var(--tm-fg-3)', fontWeight: modoPreco === m.id ? 600 : 400 }}>
              {m.l}
            </button>
          ))}
        </div>
      </div>
      <table className="tbl" style={{ fontSize: 12.5 }}>
        <thead><tr>
          <th>Produto</th><th style={{ width: 90 }}>Unidades</th>
          <th style={{ width: 130 }} className="num right">{modoPreco === 'bruto' ? 'Vendas brutas (R$)' : 'Preço unit (R$)'}</th>
          <th style={{ width: 120 }} className="num right">{modoPreco === 'bruto' ? 'Preço médio' : 'Total'}</th>
          <th style={{ width: 36 }}></th>
        </tr></thead>
        <tbody>
          {linhas.map((l, i) => {
            const cd = convDados(l);
            const nb = { borderBottom: 'none' };
            return (
            <React.Fragment key={i}>
            <tr>
              <td style={nb}><SearchableSelect value={l.produtoId} options={prodOpts} placeholder="Buscar produto (SKU/nome)…"
                onChange={(id) => escolherProduto(i, id)} /></td>
              <td style={nb}><input className="input" type="number" min="1" step="1" value={l.qty} onChange={e => setLinha(i, { qty: e.target.value })} style={{ padding: '4px 8px' }} /></td>
              <td className="num right" style={nb}>
                {modoPreco === 'bruto'
                  ? <input className="input" type="number" min="0" step="0.01" placeholder="0,00" value={l.bruto} onChange={e => setLinha(i, { bruto: e.target.value })} style={{ padding: '4px 8px', textAlign: 'right' }} />
                  : <input className="input" type="number" min="0" step="0.01" placeholder="0,00" value={l.preco} onChange={e => setLinha(i, { preco: e.target.value })} style={{ padding: '4px 8px', textAlign: 'right' }} />}
              </td>
              <td className="num right muted" style={nb}>
                {modoPreco === 'bruto'
                  ? (Number(l.qty) > 0 && brutoDe(l) > 0 ? `R$ ${brl(medioDe(l))}` : '—')
                  : `R$ ${brl(brutoDe(l))}`}
              </td>
              <td style={nb}>{linhas.length > 1 && <Button variant="ghost" size="sm" icon="x" title="Remover linha" onClick={() => rmLinha(i)} />}</td>
            </tr>
            <tr>
              <td colSpan={5} style={{ paddingTop: 0, paddingBottom: 12 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap', fontSize: 11.5, color: 'var(--tm-fg-4)' }}>
                  <span style={{ fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.06em', fontSize: 9.5 }}>
                    Métricas do anúncio <span style={{ fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>(opcional)</span>
                  </span>
                  <label style={{ display: 'flex', alignItems: 'center', gap: 5 }}>Visitas
                    <input className="input" type="number" min="0" step="1" placeholder="—" value={l.visitas}
                      onChange={e => setLinha(i, { visitas: e.target.value })} style={{ width: 74, padding: '3px 6px', textAlign: 'right' }} /></label>
                  <label style={{ display: 'flex', alignItems: 'center', gap: 5 }}>Vendas (pedidos)
                    <input className="input" type="number" min="0" step="1" placeholder="—" value={l.qtdVendas}
                      onChange={e => setLinha(i, { qtdVendas: e.target.value })} style={{ width: 64, padding: '3px 6px', textAlign: 'right' }} /></label>
                  <label style={{ display: 'flex', alignItems: 'center', gap: 5 }}>Conversão do relatório
                    <input className="input" type="number" min="0" step="0.01" placeholder="—" value={l.conversao}
                      onChange={e => setLinha(i, { conversao: e.target.value })} style={{ width: 64, padding: '3px 6px', textAlign: 'right' }} />%</label>
                  {cd
                    ? <span style={{ marginLeft: 'auto', fontWeight: 600, color: 'var(--tm-fg-2)' }}>
                        Conversão calculada: {fmtPct(cd.pct)} <span style={{ fontWeight: 400, color: 'var(--tm-fg-4)' }}>(base: {cd.base})</span>
                        {temNum(l.conversao) && Math.abs((Number(l.conversao) || 0) - cd.pct) > 0.1
                          ? <span style={{ color: 'var(--tm-warning)', fontWeight: 400 }}> · relatório: {fmtPct(l.conversao)}</span> : null}
                      </span>
                    : (temNum(l.conversao)
                        ? <span style={{ marginLeft: 'auto' }}>Relatório: {fmtPct(l.conversao)} · informe visitas p/ calcular</span>
                        : <span style={{ marginLeft: 'auto' }}>informe visitas p/ calcular a conversão</span>)}
                </div>
              </td>
            </tr>
            </React.Fragment>
          ); })}
        </tbody>
      </table>
      <div style={{ marginTop: 8, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <Button variant="secondary" size="sm" icon="plus" onClick={addLinha}>Adicionar produto</Button>
        <div style={{ fontSize: 14, fontWeight: 700 }}>Venda cheia: R$ {brl(total)}</div>
      </div>
      <div style={{ fontSize: 11.5, color: 'var(--tm-fg-4)', marginTop: 8 }}>
        Padrão: digite <b>unidades</b> e <b>vendas brutas</b> (o total da linha, como vem no relatório do
        marketplace) — o preço médio é calculado. Se um produto teve preços diferentes na semana, dá pra
        separar em duas linhas. A venda entra pelo valor cheio; a taxa vira despesa no repasse (Fase 3).
        As <b>métricas do anúncio</b> (visitas, vendas, conversão) são <b>opcionais</b> — deixar em branco
        não impede o lançamento. A <b>conversão é calculada</b> (vendas ÷ visitas, ou unidades ÷ visitas
        quando você não informa as vendas); o campo "conversão do relatório" só guarda o número que o
        marketplace mostra, pra comparar depois.
      </div>
      {err && <div style={{ fontSize: 12.5, color: 'var(--tm-danger)', marginTop: 10 }}>{err}</div>}
    </Drawer>
  );
}

// Drawer "Ver detalhes" — linhas (produto, qtd, preço, custo), total, período, status.
function LancamentoDetalhe({ pedido, loja, onClose }) {
  const [itens, setItens] = React.useState(null);
  React.useEffect(() => { (async () => { setItens(window.tmDb ? await window.tmDb.loadPedidoItens(pedido.id) : []); })(); }, [pedido.id]);
  const total = (itens || []).reduce((a, it) => a + (Number(it.qty) || 0) * (Number(it.precoLista) || 0), 0);
  const custoTotal = (itens || []).reduce((a, it) => a + (Number(it.qty) || 0) * (Number(it.precoCusto) || 0), 0);
  const per = (pedido.periodo_inicio && pedido.periodo_fim) ? periodoLabel(pedido.periodo_inicio, pedido.periodo_fim) : (fmtDate(pedido.data_venda) || '—');
  // Conversão calculada por item (mesma regra do form): vendas ÷ visitas, ou unidades ÷ visitas.
  const rowConv = (it) => {
    const v = Number(it.visitas) || 0;
    if (it.visitas == null || it.visitas === '' || v <= 0) return null;
    const usouV = it.qtdVendas != null && it.qtdVendas !== '';
    const base = usouV ? (Number(it.qtdVendas) || 0) : (Number(it.qty) || 0);
    return (base / v) * 100;
  };
  const temMetricas = (itens || []).some(it => it.visitas != null && it.visitas !== '');
  return (
    <Drawer open={true} width={720} title={`Lançamento ${pedido.num || pedido.numero}`}
      subtitle={`${loja ? loja.nome + ' · ' + loja.plataforma : ''} · ${per}`}
      onClose={onClose} footer={<><span style={{ flex: 1 }} /><Button variant="secondary" size="sm" onClick={onClose}>Fechar</Button></>}>
      {itens === null ? <div style={{ padding: '20px 0', color: 'var(--tm-fg-3)' }}>Carregando…</div> : (
        <table className="tbl" style={{ fontSize: 12.5 }}>
          <thead><tr><th>Produto</th><th className="num right">Qtd</th><th className="num right">Preço</th><th className="num right">Custo</th>
            {temMetricas && <th className="num right">Anúncio</th>}<th className="num right">Total</th></tr></thead>
          <tbody>
            {itens.map((it, i) => {
              const conv = rowConv(it);
              return (
              <tr key={i}>
                <td><span className="ref-mono">{it.sku}</span> {it.desc}</td>
                <td className="num right">{it.qty}</td>
                <td className="num right">R$ {brl(it.precoLista)}</td>
                <td className="num right muted">{it.precoCusto != null ? `R$ ${brl(it.precoCusto)}` : '—'}</td>
                {temMetricas && <td className="num right muted" style={{ whiteSpace: 'nowrap' }}>
                  {it.visitas != null && it.visitas !== ''
                    ? `${it.visitas} vis${conv != null ? ' · ' + conv.toFixed(2).replace('.', ',') + '%' : ''}`
                    : '—'}
                </td>}
                <td className="num right">R$ {brl((Number(it.qty) || 0) * (Number(it.precoLista) || 0))}</td>
              </tr>
            ); })}
            <tr style={{ borderTop: '2px solid var(--tm-brand-champagne)', fontWeight: 700 }}>
              <td colSpan={3}>Total</td>
              <td className="num right muted">R$ {brl(custoTotal)}</td>
              {temMetricas && <td></td>}
              <td className="num right">R$ {brl(total)}</td>
            </tr>
          </tbody>
        </table>
      )}
      <div style={{ fontSize: 11.5, color: 'var(--tm-fg-4)', marginTop: 10 }}>
        Status: <b>{pedido.status}</b> · venda cheia R$ {brl(pedido.total)}. Quando o marketplace depositar, use <b>Registrar repasse</b> (ícone 🏛 na lista) pra informar o líquido — o app dá baixa no recebível e lança a taxa.
      </div>
    </Drawer>
  );
}

// Confirmação de cancelamento — mostra o que será estornado antes de aplicar.
function CancelConfirm({ pedido, loja, itens, onDone, onClose }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const confirmar = async () => {
    setBusy(true); setErr('');
    try { await cancelarLancamento(pedido, itens); onDone(); }
    catch (e) { setErr(String((e && e.message) || e)); setBusy(false); }
  };
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 500, background: 'rgba(0,0,0,0.65)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div onClick={e => e.stopPropagation()} style={{ background: 'var(--tm-bg-1)', borderRadius: 14, width: 560, border: '1px solid var(--tm-line-1)', boxShadow: '0 24px 64px rgba(0,0,0,0.5)' }}>
        <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--tm-line-1)' }}>
          <div style={{ fontFamily: 'var(--tm-font-display)', fontSize: 18 }}>Cancelar lançamento {pedido.num || pedido.numero}?</div>
          <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>{loja ? loja.nome : ''} · estorna tudo que o lançamento causou.</div>
        </div>
        <div style={{ padding: '18px 22px', fontSize: 13 }}>
          <div style={{ marginBottom: 10 }}>Será estornado:</div>
          <ul style={{ margin: 0, paddingLeft: 18, lineHeight: 1.7 }}>
            <li><b>Estoque:</b> {itens.length} produto(s) devolvidos — Entrada auditável "Cancelamento lançamento marketplace" (o movimento original NÃO é apagado).</li>
            <li><b>Recebível:</b> o título aberto é removido.</li>
            <li><b>Pedido:</b> vira <b>Cancelado</b>.</li>
          </ul>
          {err && <div style={{ fontSize: 12.5, color: 'var(--tm-danger)', marginTop: 10 }}>{err}</div>}
        </div>
        <div style={{ padding: '14px 22px', borderTop: '1px solid var(--tm-line-1)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <Button variant="secondary" size="sm" onClick={onClose}>Voltar</Button>
          <Button variant="danger-ghost" size="sm" icon="trash-2" onClick={confirmar} disabled={busy}>{busy ? 'Cancelando…' : 'Cancelar lançamento'}</Button>
        </div>
      </div>
    </div>
  );
}

// Drawer "Registrar repasse" — informa o LÍQUIDO (PIX) + data; deriva a taxa (bruto − líquido)
// e mostra o efeito no banco. Confirma → registrarRepasse (baixa recebível + cria taxa Paga).
function RepasseForm({ pedido, loja, contas, onSaved, onClose }) {
  const hoje = new Date().toISOString().slice(0, 10);
  const [rec, setRec] = React.useState(undefined);  // undefined=carregando, null=não achou
  const [liquido, setLiquido] = React.useState('');
  const [data, setData] = React.useState(String(pedido.periodo_fim || '').slice(0, 10) || hoje);
  const [contaId, setContaId] = React.useState((loja && loja.conta_id) || '');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');

  React.useEffect(() => { (async () => {
    if (!window.tmSupabase) { setRec(null); return; }
    const { data: crs } = await window.tmSupabase.from('contas_receber').select('id,valor,status,valor_recebido').eq('pedido_id', pedido.id);
    const aberto = (crs || []).find(r => !(Number(r.valor_recebido) > 0 || r.status === 'Recebido' || r.status === 'Parcial'));
    setRec(aberto || null);
  })(); }, [pedido.id]);

  const contasAtivas = (contas || []).filter(c => c.situacao !== 'Arquivada');
  const contaNome = (id) => { const c = (contas || []).find(x => x.id === id); return c ? c.nome : '—'; };
  const bruto = Number(rec && rec.valor) || Number(pedido.total) || 0;
  const liq = Number(liquido) || 0;
  const taxa = Math.round((bruto - liq) * 100) / 100;
  const taxaPct = bruto > 0 ? (taxa / bruto) * 100 : 0;
  const excede = liquido !== '' && liq > bruto;                 // borda: líquido > bruto
  const podeSalvar = rec && liq > 0 && !!contaId && !excede && !saving;

  const salvar = async () => {
    if (!rec) { setErr('Recebível aberto não encontrado — o lançamento pode já ter sido baixado ou cancelado.'); return; }
    if (liq <= 0) { setErr('Informe o líquido que caiu (PIX).'); return; }
    if (excede) { setErr('O líquido é maior que a venda cheia — não dá pra registrar (taxa negativa).'); return; }
    if (!contaId) { setErr('Escolha a conta onde o PIX caiu.'); return; }
    setSaving(true); setErr('');
    const r = await registrarRepasse(pedido, loja, contaId, liq, data || null, rec);
    setSaving(false);
    if (r.error) { setErr(r.error.message || 'Erro ao registrar o repasse.'); return; }
    onSaved();
  };

  const per = (pedido.periodo_inicio && pedido.periodo_fim) ? periodoLabel(pedido.periodo_inicio, pedido.periodo_fim) : (fmtDate(pedido.data_venda) || '—');
  return (
    <Drawer open={true} width={560} title="Registrar repasse"
      subtitle={`${loja ? loja.nome + ' · ' + loja.plataforma : ''} · ${per}`}
      onClose={onClose}
      footer={<>
        <span style={{ flex: 1 }} />
        <Button variant="secondary" size="sm" onClick={onClose}>Cancelar</Button>
        <Button variant="primary" size="sm" icon="check" onClick={salvar} disabled={!podeSalvar}>
          {saving ? 'Registrando…' : 'Registrar repasse'}
        </Button>
      </>}>
      {rec === undefined ? <div style={{ padding: '20px 0', color: 'var(--tm-fg-3)' }}>Carregando…</div>
       : rec === null ? <div style={{ fontSize: 12.5, color: 'var(--tm-danger)' }}>Recebível aberto não encontrado — talvez já baixado ou cancelado.</div>
       : (<>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '4px 0 14px', borderBottom: '1px solid var(--tm-line-1)' }}>
          <span style={{ color: 'var(--tm-fg-3)', fontSize: 12.5 }}>Venda cheia</span>
          <span style={{ fontSize: 18, fontWeight: 700 }}>R$ {brl(bruto)}</span>
        </div>

        <div className="field-grid-2" style={{ marginTop: 14 }}>
          <Field label="Líquido recebido (PIX) *" hint="O valor que realmente caiu no banco">
            <input className="input" type="number" min="0" step="0.01" placeholder="0,00" value={liquido}
              onChange={e => setLiquido(e.target.value)} style={{ textAlign: 'right' }} />
          </Field>
          <Field label="Data do repasse *"><input className="input" type="date" value={data} onChange={e => setData(e.target.value)} /></Field>
        </div>
        <Field label="Conta onde o PIX caiu *" hint={loja && loja.conta_id ? 'Vem da loja — dá pra trocar' : 'A loja ainda não tem conta — vai ficar guardada nela'}>
          <select className="input" value={contaId} onChange={e => setContaId(e.target.value)}>
            <option value="">Selecionar…</option>
            {contasAtivas.map(c => <option key={c.id} value={c.id}>{c.nome}</option>)}
            {contaId && !contasAtivas.some(c => c.id === contaId) && <option value={contaId}>{contaNome(contaId)}</option>}
          </select>
        </Field>

        {excede ? (
          <div style={{ marginTop: 14, padding: '12px 14px', borderRadius: 'var(--tm-radius-sm)', fontSize: 12.5,
            color: 'var(--tm-danger)', background: 'color-mix(in srgb, var(--tm-danger) 10%, transparent)', border: '1px solid color-mix(in srgb, var(--tm-danger) 30%, transparent)' }}>
            <b>O líquido é maior que a venda cheia.</b> Isso geraria uma taxa negativa, então não registro.
            Numa taxa de marketplace o líquido é sempre ≤ a venda. Confira o valor; se de fato entrou <i>mais</i> que
            a venda (bonificação, reembolso, ajuste), me diga que a gente lança isso à parte — não como taxa.
          </div>
        ) : (
          <div style={{ marginTop: 16, padding: '12px 14px', borderRadius: 'var(--tm-radius-sm)', background: 'var(--tm-bg-2)', border: '1px solid var(--tm-line-1)', fontSize: 12.5 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
              <span style={{ color: 'var(--tm-fg-3)' }}>Recebível cheio → <b style={{ color: 'var(--tm-success)' }}>Recebido</b></span>
              <span style={{ color: 'var(--tm-success)', fontWeight: 600 }}>+ R$ {brl(bruto)}</span>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
              <span style={{ color: 'var(--tm-fg-3)' }}>Taxa de marketplace → despesa <b>Paga</b>{taxa > 0 ? ` (${taxaPct.toFixed(1).replace('.', ',')}%)` : ''}</span>
              <span style={{ color: 'var(--tm-danger)', fontWeight: 600 }}>− R$ {brl(taxa)}</span>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: 8, borderTop: '1px solid var(--tm-line-1)', fontWeight: 700 }}>
              <span>Líquido no banco</span><span>R$ {brl(bruto - taxa)}</span>
            </div>
            {taxa === 0 && liq > 0 && <div style={{ marginTop: 8, color: 'var(--tm-fg-4)' }}>Sem taxa neste repasse — não crio despesa.</div>}
            <div style={{ marginTop: 8, color: 'var(--tm-fg-4)', fontSize: 11.5 }}>
              A <b>receita</b> continua cheia (R$ {brl(bruto)}); a taxa entra como <b>despesa comercial</b> no DRE.
            </div>
          </div>
        )}
        {err && <div style={{ fontSize: 12.5, color: 'var(--tm-danger)', marginTop: 12 }}>{err}</div>}
       </>)}
    </Drawer>
  );
}

function MarketplaceLancamentos({ onNav }) {   // eslint-disable-line no-unused-vars
  const ped = usePedidosList([]);
  const lojasHook = useMktLojasList([]);
  const prodHook = useProdutosList([]);
  const contasHook = useContasList([]);
  const [novo, setNovo] = React.useState(false);
  const [repassando, setRepassando] = React.useState(null);   // pedido
  const [detalhe, setDetalhe] = React.useState(null);
  const [editando, setEditando] = React.useState(null);     // { pedido, itens }
  const [cancelando, setCancelando] = React.useState(null); // { pedido, itens }
  const [recByPedido, setRecByPedido] = React.useState({});
  const [busy, setBusy] = React.useState(false);

  const lojasAtivas = (lojasHook.rows || []).filter(l => l.situacao !== 'Arquivada');
  const lojaById = {}; (lojasHook.rows || []).forEach(l => { lojaById[l.id] = l; });
  const lancamentos = (ped.rows || []).filter(p => p.marketplace_loja_id && p.status !== 'Cancelado')
    .sort((a, b) => String(b.data_venda || b.created_at || '').localeCompare(String(a.data_venda || a.created_at || '')));
  const fmtPeriodo = (p) => (p.periodo_inicio && p.periodo_fim) ? periodoLabel(p.periodo_inicio, p.periodo_fim) : (fmtDate(p.data_venda) || '—');

  const loadRec = React.useCallback(async () => {
    if (!window.tmSupabase) return;
    const ids = (ped.rows || []).filter(p => p.marketplace_loja_id).map(p => p.id);
    if (!ids.length) { setRecByPedido({}); return; }
    const { data } = await window.tmSupabase.from('contas_receber').select('id,pedido_id,valor_recebido,status').in('pedido_id', ids);
    const m = {}; (data || []).forEach(r => { (m[r.pedido_id] = m[r.pedido_id] || []).push(r); });
    setRecByPedido(m);
  }, [ped.rows]);   // eslint-disable-line
  React.useEffect(() => { loadRec(); }, [loadRec]);

  const temRecebido = (p) => recebimentosDe(recByPedido[p.id] || []).length > 0;
  const recarregar = () => { ped.reload(); loadRec(); };
  const abrirEdit = async (p) => {
    if (temRecebido(p)) { alert('Repasse já registrado — estorne o repasse primeiro (Fase 3). Não se edita venda com recebimento.'); return; }
    setBusy(true); const itens = await window.tmDb.loadPedidoItens(p.id); setBusy(false); setEditando({ pedido: p, itens });
  };
  const abrirCancel = async (p) => {
    if (temRecebido(p)) { alert('Repasse já registrado — estorne o repasse primeiro (Fase 3). Não se cancela venda com recebimento.'); return; }
    setBusy(true); const itens = await window.tmDb.loadPedidoItens(p.id); setBusy(false); setCancelando({ pedido: p, itens });
  };

  return (
    <div className="canvas">
      <PageHead title="Marketplace · Lançamentos" sub={`${lancamentos.length} lançamento${lancamentos.length !== 1 ? 's' : ''}`}
        right={<Button variant="primary" icon="plus" size="sm" disabled={lojasAtivas.length === 0} onClick={() => setNovo(true)}>Novo lançamento</Button>} />

      {lojasAtivas.length === 0 && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '0 0 16px', padding: '10px 14px', borderRadius: 'var(--tm-radius-sm)', fontSize: 12.5,
          color: 'var(--tm-warning)', background: 'color-mix(in srgb, var(--tm-warning) 12%, transparent)', border: '1px solid color-mix(in srgb, var(--tm-warning) 30%, transparent)' }}>
          <Icon name="alert-circle" size={15} /> <span>Cadastre uma loja primeiro em <b>Marketplace › Lojas</b>.</span>
        </div>
      )}

      <Card>
        {lancamentos.length === 0 ? (
          <div style={{ padding: '48px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>
            <Icon name="shopping-bag" size={36} style={{ opacity: 0.3, marginBottom: 12 }} />
            <div style={{ fontSize: 14, marginBottom: 6 }}>Nenhum lançamento</div>
            <div style={{ fontSize: 12 }}>Registre o resumo semanal de vendas de cada loja.</div>
          </div>
        ) : (
          <table className="tbl">
            <thead><tr><th>Nº</th><th>Loja</th><th>Período</th><th>Status</th><th className="num right">Venda cheia</th><th></th></tr></thead>
            <tbody>
              {lancamentos.map((p) => {
                const rec = temRecebido(p);
                return (
                  <tr key={p.id} className="clickable" onClick={() => setDetalhe(p)}>
                    <td><span className="ref-mono gold">{p.num || p.numero}</span></td>
                    <td>{lojaById[p.marketplace_loja_id] ? lojaById[p.marketplace_loja_id].nome : '—'}</td>
                    <td className="muted">{fmtPeriodo(p)}</td>
                    <td><Badge tone="success">{p.status}</Badge>{rec && <span title="Repasse registrado" style={{ marginLeft: 6, fontSize: 10.5, color: 'var(--tm-success)' }}>· repasse ✓</span>}</td>
                    <td className="num right" style={{ fontWeight: 600 }}>R$ {brl(p.total)}</td>
                    <td onClick={e => e.stopPropagation()} style={{ whiteSpace: 'nowrap' }}>
                      <Button variant="ghost" size="sm" icon="eye" title="Ver detalhes" onClick={() => setDetalhe(p)} />
                      <Button variant="ghost" size="sm" icon="landmark" disabled={rec || busy} title={rec ? 'Repasse já registrado' : 'Registrar repasse (líquido + taxa)'} onClick={() => setRepassando(p)} />
                      <Button variant="ghost" size="sm" icon="pencil" disabled={rec || busy} title={rec ? 'Repasse registrado — estorne primeiro' : 'Editar'} onClick={() => abrirEdit(p)} />
                      <Button variant="ghost" size="sm" icon="x-circle" disabled={rec || busy} title={rec ? 'Repasse registrado — estorne primeiro' : 'Cancelar lançamento'} onClick={() => abrirCancel(p)} />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Card>

      {novo && (
        <LancamentoForm lojas={lojasAtivas} produtos={prodHook.rows || []}
          onClose={() => setNovo(false)} onSaved={() => { setNovo(false); recarregar(); }} />
      )}
      {editando && (
        <LancamentoForm lojas={lojasHook.rows || []} produtos={prodHook.rows || []} edit={editando}
          onClose={() => setEditando(null)} onSaved={() => { setEditando(null); recarregar(); }} />
      )}
      {repassando && (
        <RepasseForm pedido={repassando} loja={lojaById[repassando.marketplace_loja_id]} contas={contasHook.rows || []}
          onClose={() => setRepassando(null)} onSaved={() => { setRepassando(null); recarregar(); }} />
      )}
      {detalhe && <LancamentoDetalhe pedido={detalhe} loja={lojaById[detalhe.marketplace_loja_id]} onClose={() => setDetalhe(null)} />}
      {cancelando && (
        <CancelConfirm pedido={cancelando.pedido} loja={lojaById[cancelando.pedido.marketplace_loja_id]} itens={cancelando.itens}
          onClose={() => setCancelando(null)} onDone={() => { setCancelando(null); recarregar(); }} />
      )}
    </div>
  );
}

// ─── Painel do módulo (Fase 4): Receita por canal + KPIs por plataforma ──────
// Tudo derivado das tabelas existentes (zero SQL):
//   receita bruta = Σ total dos lançamentos (não cancelados) no período;
//   taxa total    = Σ contas_pagar "Taxa de marketplace" (Pago) amarradas ao lançamento (pedido_id);
//   taxa %        = taxa ÷ receita JÁ REPASSADA (honesto: só entra bruto de quem já teve repasse);
//   CMV           = Σ preco_custo (snapshot da venda) × qtd dos itens do lançamento;
//   margem        = receita bruta − CMV − taxa.
// "Receita por canal" compara B2B (marketplace_loja_id IS NULL) × Marketplace (por plataforma).
function MarketplacePainel({ onNav }) {   // eslint-disable-line no-unused-vars
  const per = useFinPeriodo();
  const [raw, setRaw] = React.useState(null);   // null = carregando
  const [erro, setErro] = React.useState(null);

  React.useEffect(() => { (async () => {
    if (!window.tmSupabase) { setRaw({ mkt: [], b2b: [], lojas: [], itens: [], rec: [], pag: [] }); return; }
    setRaw(null); setErro(null);
    try {
      const [mktRes, b2bRes, lojasRes, itensRes, recRes, pagRes] = await Promise.all([
        window.tmSupabase.from('pedidos').select('id,total,status,marketplace_loja_id,data_venda,periodo_inicio,periodo_fim,created_at').not('marketplace_loja_id', 'is', null).neq('status', 'Cancelado'),
        window.tmSupabase.from('pedidos').select('total,data_venda,created_at').is('marketplace_loja_id', null).eq('status', 'Atendido'),
        window.tmSupabase.from('marketplace_lojas').select('id,nome,plataforma'),
        window.tmSupabase.from('pedido_itens').select('pedido_id,quantidade,preco_custo'),
        window.tmSupabase.from('contas_receber').select('pedido_id,status,valor_recebido'),
        window.tmSupabase.from('contas_pagar').select('pedido_id,valor,status,categoria').eq('categoria', 'Taxa de marketplace'),
      ]);
      const firstErr = [mktRes, b2bRes, lojasRes, itensRes, recRes, pagRes].map(r => r && r.error).find(Boolean);
      if (firstErr) { setErro(firstErr); setRaw({ mkt: [], b2b: [], lojas: [], itens: [], rec: [], pag: [] }); return; }
      setRaw({ mkt: mktRes.data || [], b2b: b2bRes.data || [], lojas: lojasRes.data || [], itens: itensRes.data || [], rec: recRes.data || [], pag: pagRes.data || [] });
    } catch (e) { setErro(e); setRaw({ mkt: [], b2b: [], lojas: [], itens: [], rec: [], pag: [] }); }
  })(); }, []);

  const dados = React.useMemo(() => {
    if (!raw) return null;
    const iv = per.intervalo || {};
    const inicio = iv.inicio || null, fim = iv.fim || null;
    const dref = (p) => String(p.data_venda || p.created_at || '').slice(0, 10);
    const inRange = (d) => d && (!inicio || d >= inicio) && (!fim || d <= fim);

    const mkt = (raw.mkt || []).filter(p => inRange(dref(p)));
    const lojaById = {}; (raw.lojas || []).forEach(l => { lojaById[l.id] = l; });
    const platOf = (p) => (lojaById[p.marketplace_loja_id] && lojaById[p.marketplace_loja_id].plataforma) || 'Outra';
    const mktIds = new Set(mkt.map(p => p.id));

    const taxaByPed = {}; (raw.pag || []).forEach(r => { if (r.status === 'Pago') taxaByPed[r.pedido_id] = (taxaByPed[r.pedido_id] || 0) + (Number(r.valor) || 0); });
    const repassado = {}; (raw.rec || []).forEach(r => { if (Number(r.valor_recebido) > 0 || r.status === 'Recebido') repassado[r.pedido_id] = true; });
    const cmvByPed = {}; let semCusto = 0;
    (raw.itens || []).forEach(it => {
      if (!mktIds.has(it.pedido_id)) return;
      if (it.preco_custo == null) semCusto++;
      cmvByPed[it.pedido_id] = (cmvByPed[it.pedido_id] || 0) + ((Number(it.preco_custo) || 0) * (Number(it.quantidade) || 0));
    });

    const plat = {};
    mkt.forEach(p => {
      const k = platOf(p);
      const g = plat[k] || (plat[k] = { plataforma: k, bruto: 0, cmv: 0, taxa: 0, brutoRepassado: 0, nLanc: 0, nRepassado: 0 });
      const b = Number(p.total) || 0;
      g.bruto += b; g.nLanc++;
      g.cmv += cmvByPed[p.id] || 0;
      g.taxa += taxaByPed[p.id] || 0;
      if (repassado[p.id]) { g.brutoRepassado += b; g.nRepassado++; }
    });
    const plats = Object.values(plat).sort((a, b) => b.bruto - a.bruto);
    plats.forEach(g => { g.taxaPct = g.brutoRepassado > 0 ? (g.taxa / g.brutoRepassado) * 100 : null; g.margem = g.bruto - g.cmv - g.taxa; });

    const tot = plats.reduce((a, g) => ({
      bruto: a.bruto + g.bruto, cmv: a.cmv + g.cmv, taxa: a.taxa + g.taxa,
      brutoRepassado: a.brutoRepassado + g.brutoRepassado, nLanc: a.nLanc + g.nLanc, nRepassado: a.nRepassado + g.nRepassado,
    }), { bruto: 0, cmv: 0, taxa: 0, brutoRepassado: 0, nLanc: 0, nRepassado: 0 });
    tot.taxaPct = tot.brutoRepassado > 0 ? (tot.taxa / tot.brutoRepassado) * 100 : null;
    tot.margem = tot.bruto - tot.cmv - tot.taxa;

    const b2bReceita = (raw.b2b || []).filter(p => inRange(dref(p))).reduce((a, p) => a + (Number(p.total) || 0), 0);
    const canalTotal = b2bReceita + tot.bruto;

    return { plats, tot, b2bReceita, mktReceita: tot.bruto, canalTotal, semCusto };
  }, [raw, per.preset, per.custom && per.custom.inicio, per.custom && per.custom.fim]);

  const pct = (n) => (Number(n) || 0).toFixed(1).replace('.', ',') + '%';
  const share = (v, tot) => tot > 0 ? (v / tot) * 100 : 0;

  return (
    <div className="canvas">
      <PageHead title="Marketplace · Painel" sub="Receita por canal, taxa e margem por plataforma"
        right={<Button variant="secondary" icon="shopping-bag" size="sm" onClick={() => onNav && onNav('marketplace/lancamentos')}>Lançamentos</Button>} />
      <PeriodoFilter aba="marketplace" />

      {erro ? (
        <Card><div style={{ padding: '24px 0', textAlign: 'center', color: 'var(--tm-danger)' }}>Erro ao carregar: {String((erro && erro.message) || erro)}</div></Card>
      ) : !dados ? (
        <Card><div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>Carregando…</div></Card>
      ) : (<>
        <div className="kpi-row" style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 16 }}>
          <KPI label="Receita bruta (marketplace)" value={`R$ ${brl(dados.mktReceita)}`} />
          <KPI label="Taxa total" value={`R$ ${brl(dados.tot.taxa)}`} />
          <KPI label="Taxa % (sobre repassado)" value={dados.tot.taxaPct != null ? pct(dados.tot.taxaPct) : '—'} />
          <KPI label="Margem (bruto − CMV − taxa)" value={`R$ ${brl(dados.tot.margem)}`} />
        </div>

        <Card title="Receita por canal" style={{ marginBottom: 16 }}>
          {dados.canalTotal === 0 ? (
            <div style={{ padding: '20px 0', color: 'var(--tm-fg-3)', fontSize: 13 }}>Sem receita no período.</div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              {[{ nome: 'B2B', valor: dados.b2bReceita, cor: 'var(--tm-info)' }, { nome: 'Marketplace', valor: dados.mktReceita, cor: 'var(--tm-brand-champagne)' }].map(c => (
                <div key={c.nome}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12.5, marginBottom: 5 }}>
                    <span style={{ color: 'var(--tm-fg-1)', fontWeight: 600 }}>{c.nome}</span>
                    <span style={{ color: 'var(--tm-fg-2)' }}>R$ {brl(c.valor)} <span style={{ color: 'var(--tm-fg-4)' }}>· {pct(share(c.valor, dados.canalTotal))}</span></span>
                  </div>
                  <div style={{ height: 10, borderRadius: 5, background: 'var(--tm-bg-3)', overflow: 'hidden' }}>
                    <div style={{ width: share(c.valor, dados.canalTotal) + '%', height: '100%', background: c.cor }} />
                  </div>
                </div>
              ))}
              <div style={{ fontSize: 11.5, color: 'var(--tm-fg-4)', marginTop: 2 }}>
                Total no período: R$ {brl(dados.canalTotal)} · B2B pelo faturamento dos pedidos, Marketplace pela venda cheia dos lançamentos.
              </div>
            </div>
          )}
        </Card>

        <Card title="Marketplace por plataforma">
          {dados.plats.length === 0 ? (
            <div style={{ padding: '20px 0', color: 'var(--tm-fg-3)', fontSize: 13 }}>Nenhum lançamento de marketplace no período.</div>
          ) : (
            <table className="tbl" style={{ fontSize: 12.5 }}>
              <thead><tr>
                <th>Plataforma</th><th className="num right">Lançam.</th><th className="num right">Receita bruta</th>
                <th className="num right">CMV</th><th className="num right">Taxa</th>
                <th className="num right" title="Taxa ÷ receita já repassada">Taxa %</th><th className="num right">Margem</th>
              </tr></thead>
              <tbody>
                {dados.plats.map(g => (
                  <tr key={g.plataforma}>
                    <td>{g.plataforma}{g.nRepassado < g.nLanc && <span title={`${g.nLanc - g.nRepassado} sem repasse registrado`} style={{ marginLeft: 6, fontSize: 10.5, color: 'var(--tm-warning)' }}>· {g.nLanc - g.nRepassado} s/ repasse</span>}</td>
                    <td className="num right">{g.nLanc}</td>
                    <td className="num right">R$ {brl(g.bruto)}</td>
                    <td className="num right muted">R$ {brl(g.cmv)}</td>
                    <td className="num right">R$ {brl(g.taxa)}</td>
                    <td className="num right">{g.taxaPct != null ? pct(g.taxaPct) : '—'}</td>
                    <td className="num right" style={{ fontWeight: 600, color: g.margem >= 0 ? 'var(--tm-fg-1)' : 'var(--tm-danger)' }}>R$ {brl(g.margem)}</td>
                  </tr>
                ))}
                <tr style={{ borderTop: '2px solid var(--tm-brand-champagne)', fontWeight: 700 }}>
                  <td>Total</td>
                  <td className="num right">{dados.tot.nLanc}</td>
                  <td className="num right">R$ {brl(dados.tot.bruto)}</td>
                  <td className="num right muted">R$ {brl(dados.tot.cmv)}</td>
                  <td className="num right">R$ {brl(dados.tot.taxa)}</td>
                  <td className="num right">{dados.tot.taxaPct != null ? pct(dados.tot.taxaPct) : '—'}</td>
                  <td className="num right">R$ {brl(dados.tot.margem)}</td>
                </tr>
              </tbody>
            </table>
          )}
          <div style={{ fontSize: 11.5, color: 'var(--tm-fg-4)', marginTop: 10 }}>
            <b>Taxa %</b> é calculada só sobre a receita <b>já repassada</b> (lançamentos com repasse registrado), pra refletir o custo real de cada plataforma. Lançamentos ainda sem repasse contam na receita bruta e na margem com taxa 0 até você registrar o PIX.
            {dados.semCusto > 0 && <> · {dados.semCusto} item(ns) sem custo de snapshot (CMV subestimado nesses).</>}
          </div>
        </Card>
      </>)}
    </div>
  );
}

// ─── Transição do improviso (Fase 5): reclassificar B2B → marketplace + detector ─
// Detector: pedidos B2B cujo cliente_nome NÃO casa com nenhum cadastro (cliente/salão/
// distribuidor), ou cujo nome parece de marketplace — candidatos a venda de loja própria
// lançada como B2B. NADA é alterado automaticamente; ela reclassifica (1 ou em lote).
// Reclassificar = seta marketplace_loja_id + cliente_nome (nome da loja) + canal 'Marketplace';
// o recebível NÃO é tocado (preservado, não recriado) → a invariante do caixa não se move.
function normNome(s) { return String(s || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().trim(); }
const PLAT_KEYWORDS = ['mercado livre', 'mercadolivre', 'shopee', 'tiktok', 'magalu', 'magazine luiza', 'amazon', 'americanas', 'shein', 'netshoes', 'marketplace'];
function pareceMarketplace(nome) { const n = normNome(nome); return PLAT_KEYWORDS.some(k => n.indexOf(k) !== -1); }

async function reclassificarPedidos(ids, loja) {
  // Só o pedido muda (canal). O recebível é preservado; nenhum recebimento é tocado.
  return window.tmSupabase.from('pedidos').update({
    marketplace_loja_id: loja.id, cliente_nome: loja.nome, canal: 'Marketplace',
  }).in('id', ids);
}

// Modal de confirmação — mostra o que muda antes de aplicar (1 ou vários pedidos).
function ReclassConfirm({ pedidos, lojas, onDone, onClose }) {
  const [lojaId, setLojaId] = React.useState(lojas[0] ? lojas[0].id : '');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const loja = lojas.find(l => l.id === lojaId);
  const total = pedidos.reduce((a, p) => a + (Number(p.total) || 0), 0);
  const aplicar = async () => {
    if (!loja) { setErr('Escolha a loja.'); return; }
    setBusy(true); setErr('');
    const { error } = await reclassificarPedidos(pedidos.map(p => p.id), loja);
    setBusy(false);
    if (error) { setErr('Erro: ' + (error.message || error.code)); return; }
    onDone();
  };
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 500, background: 'rgba(0,0,0,0.65)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 560, maxWidth: '92vw', background: 'var(--tm-bg-1)', borderRadius: 'var(--tm-radius-md)', boxShadow: 'var(--tm-shadow-lg)', overflow: 'hidden' }}>
        <div style={{ padding: '16px 22px', borderBottom: '1px solid var(--tm-line-1)', fontWeight: 700, fontSize: 15 }}>
          Reclassificar {pedidos.length === 1 ? 'pedido' : `${pedidos.length} pedidos`} como marketplace
        </div>
        <div style={{ padding: '18px 22px', fontSize: 13, color: 'var(--tm-fg-2)' }}>
          <Field label="Loja de marketplace *">
            <select className="input" value={lojaId} onChange={e => setLojaId(e.target.value)}>
              <option value="">Selecionar…</option>
              {lojas.map(l => <option key={l.id} value={l.id}>{l.nome} · {l.plataforma}</option>)}
            </select>
          </Field>
          <div style={{ marginTop: 14, marginBottom: 8, fontSize: 12, color: 'var(--tm-fg-3)' }}>O que muda:</div>
          <ul style={{ margin: 0, paddingLeft: 18, fontSize: 12.5, lineHeight: 1.7 }}>
            <li><b>Canal:</b> B2B → <b>Marketplace</b>{loja ? ` (loja "${loja.nome}")` : ''} — sai dos relatórios B2B e entra no Painel do marketplace.</li>
            <li><b>Cliente do pedido:</b> passa a ser o nome da loja{loja ? ` ("${loja.nome}")` : ''}.</li>
            <li><b>Recebível:</b> <b>preservado</b> — não recrio nem toco em recebimento. O saldo do banco não se move.</li>
            <li><b>Repasse:</b> se ainda não houve, você registra depois em Lançamentos, normal.</li>
          </ul>
          {pedidos.length > 1 && (
            <div style={{ marginTop: 12, maxHeight: 140, overflow: 'auto', border: '1px solid var(--tm-line-1)', borderRadius: 'var(--tm-radius-sm)', padding: '8px 10px', fontSize: 11.5, color: 'var(--tm-fg-3)' }}>
              {pedidos.map(p => <div key={p.id}>{p.num || p.numero} · {p.cliente_nome || '—'} · R$ {brl(p.total)}</div>)}
              <div style={{ marginTop: 6, fontWeight: 600, color: 'var(--tm-fg-2)' }}>Total: R$ {brl(total)}</div>
            </div>
          )}
          {err && <div style={{ fontSize: 12.5, color: 'var(--tm-danger)', marginTop: 12 }}>{err}</div>}
        </div>
        <div style={{ padding: '14px 22px', borderTop: '1px solid var(--tm-line-1)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <Button variant="secondary" size="sm" onClick={onClose}>Cancelar</Button>
          <Button variant="primary" size="sm" icon="check" onClick={aplicar} disabled={busy || !loja}>{busy ? 'Reclassificando…' : 'Reclassificar'}</Button>
        </div>
      </div>
    </div>
  );
}

function MarketplaceTransicao({ onNav }) {   // eslint-disable-line no-unused-vars
  const ped = usePedidosList([]);
  const cli = useClientesList([]);
  const sal = useSaloesList([]);
  const dist = useDistribuidoresList([]);
  const lojasHook = useMktLojasList([]);
  const [soSuspeitos, setSoSuspeitos] = React.useState(true);
  const [busca, setBusca] = React.useState('');
  const [sel, setSel] = React.useState({});
  const [reclass, setReclass] = React.useState(null);   // array de pedidos p/ confirmar

  const known = React.useMemo(() => {
    const set = new Set();
    const add = (v) => { const n = normNome(v); if (n) set.add(n); };
    (cli.rows || []).forEach(r => { add(r.nome); add(r.fantasia); });
    (sal.rows || []).forEach(r => { add(r.nome); add(r.fantasia); });
    (dist.rows || []).forEach(r => { add(r.nome); add(r.fantasia); });
    return set;
  }, [cli.rows, sal.rows, dist.rows]);

  const b2b = (ped.rows || []).filter(p => !p.marketplace_loja_id && p.status === 'Atendido');
  const analisados = b2b.map(p => {
    const n = normNome(p.cliente_nome);
    const kw = pareceMarketplace(p.cliente_nome);
    const semCadastro = !n || !known.has(n);
    const suspeito = kw || semCadastro;
    const motivo = kw ? 'nome parece marketplace' : (!n ? 'sem nome de cliente' : (semCadastro ? 'sem cadastro casando' : ''));
    return { p, suspeito, motivo, kw };
  });
  const nSuspeitos = analisados.filter(a => a.suspeito).length;

  const lojasAtivas = (lojasHook.rows || []).filter(l => l.situacao !== 'Arquivada');
  const q = normNome(busca);
  const visiveis = analisados.filter(a => {
    if (soSuspeitos && !a.suspeito) return false;
    if (q && !(normNome(a.p.cliente_nome).indexOf(q) !== -1 || String(a.p.num || a.p.numero || '').toLowerCase().indexOf(busca.toLowerCase()) !== -1)) return false;
    return true;
  }).sort((x, y) => (y.kw ? 1 : 0) - (x.kw ? 1 : 0) || String(y.p.data_venda || y.p.created_at || '').localeCompare(String(x.p.data_venda || x.p.created_at || '')));

  const selIds = Object.keys(sel).filter(k => sel[k]);
  const selPedidos = visiveis.filter(a => sel[a.p.id]).map(a => a.p);
  const toggleSel = (id) => setSel(s => Object.assign({}, s, { [id]: !s[id] }));
  const allVisSel = visiveis.length > 0 && visiveis.every(a => sel[a.p.id]);
  const toggleAll = () => { const next = {}; if (!allVisSel) visiveis.forEach(a => { next[a.p.id] = true; }); setSel(next); };
  const recarregar = () => { ped.reload(); setSel({}); };

  const semLoja = lojasAtivas.length === 0;

  return (
    <div className="canvas">
      <PageHead title="Marketplace · Transição" sub="Reclassifique vendas de loja própria que entraram como B2B"
        right={<Button variant="secondary" icon="layout-dashboard" size="sm" onClick={() => onNav && onNav('marketplace/painel')}>Painel</Button>} />

      {semLoja && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '0 0 16px', padding: '10px 14px', borderRadius: 'var(--tm-radius-sm)', fontSize: 12.5,
          color: 'var(--tm-warning)', background: 'color-mix(in srgb, var(--tm-warning) 12%, transparent)', border: '1px solid color-mix(in srgb, var(--tm-warning) 30%, transparent)' }}>
          <Icon name="alert-circle" size={15} /> <span>Cadastre uma loja primeiro em <b>Marketplace › Lojas</b> pra poder reclassificar.</span>
        </div>
      )}

      <Card>
        <div className="toolbar" style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 12, flexWrap: 'wrap' }}>
          <div style={{ display: 'flex', gap: 4 }}>
            {[{ id: true, l: `Suspeitos (${nSuspeitos})` }, { id: false, l: 'Todos os B2B' }].map(t => (
              <button key={String(t.id)} type="button" onClick={() => setSoSuspeitos(t.id)}
                style={{ padding: '5px 12px', fontSize: 12, cursor: 'pointer', borderRadius: 'var(--tm-radius-sm)',
                  border: '1px solid ' + (soSuspeitos === t.id ? 'var(--tm-brand-champagne)' : 'var(--tm-line-2)'),
                  background: soSuspeitos === t.id ? 'color-mix(in srgb, var(--tm-brand-champagne) 14%, transparent)' : 'var(--tm-bg-2)',
                  color: soSuspeitos === t.id ? 'var(--tm-brand-champagne-deep, var(--tm-fg-1))' : 'var(--tm-fg-3)', fontWeight: soSuspeitos === t.id ? 600 : 400 }}>
                {t.l}
              </button>
            ))}
          </div>
          <input className="input" placeholder="Buscar por cliente ou número…" value={busca} onChange={e => setBusca(e.target.value)} style={{ maxWidth: 260 }} />
          <span style={{ flex: 1 }} />
          {selIds.length > 0 && (
            <Button variant="primary" size="sm" icon="shuffle" disabled={semLoja} onClick={() => setReclass(selPedidos)}>
              Reclassificar {selIds.length} selecionado{selIds.length > 1 ? 's' : ''}
            </Button>
          )}
        </div>

        {visiveis.length === 0 ? (
          <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>
            <Icon name="check-circle" size={32} style={{ opacity: 0.3, marginBottom: 10 }} />
            <div style={{ fontSize: 13 }}>{soSuspeitos ? 'Nenhum pedido B2B suspeito.' : 'Nenhum pedido B2B.'}</div>
          </div>
        ) : (
          <table className="tbl" style={{ fontSize: 12.5 }}>
            <thead><tr>
              <th style={{ width: 32 }}><input type="checkbox" checked={allVisSel} onChange={toggleAll} /></th>
              <th>Nº</th><th>Cliente atual</th><th>Data</th><th className="num right">Total</th><th>Sinal</th><th></th>
            </tr></thead>
            <tbody>
              {visiveis.map(({ p, suspeito, motivo, kw }) => (
                <tr key={p.id}>
                  <td><input type="checkbox" checked={!!sel[p.id]} onChange={() => toggleSel(p.id)} /></td>
                  <td><span className="ref-mono">{p.num || p.numero}</span></td>
                  <td>{p.cliente_nome || <span className="muted">— sem nome</span>}</td>
                  <td className="muted">{fmtDate(p.data_venda) || (p.created_at ? String(p.created_at).slice(0, 10).split('-').reverse().join('/') : '—')}</td>
                  <td className="num right" style={{ fontWeight: 600 }}>R$ {brl(p.total)}</td>
                  <td>{suspeito ? <Badge tone={kw ? 'warning' : 'neutral'}>{motivo}</Badge> : <span className="muted">—</span>}</td>
                  <td onClick={e => e.stopPropagation()} style={{ whiteSpace: 'nowrap' }}>
                    <Button variant="ghost" size="sm" icon="shuffle" disabled={semLoja} title="Reclassificar como marketplace" onClick={() => setReclass([p])} />
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
        <div style={{ fontSize: 11.5, color: 'var(--tm-fg-4)', marginTop: 10 }}>
          <b>Suspeito</b> = o cliente do pedido não casa com nenhum cadastro (cliente/salão/distribuidor) ou o nome parece de marketplace. Nada é alterado sozinho — a reclassificação só acontece quando você confirma. Pra achar um pedido que <i>casa</i> com um cadastro (ex.: lançado com nome de distribuidor), troque pra <b>Todos os B2B</b> e busque.
        </div>
      </Card>

      {reclass && (
        <ReclassConfirm pedidos={reclass} lojas={lojasAtivas}
          onClose={() => setReclass(null)} onDone={() => { setReclass(null); recarregar(); }} />
      )}
    </div>
  );
}

Object.assign(window, { MarketplaceLojas, MarketplaceLancamentos, MarketplacePainel, MarketplaceTransicao });
