/**
 * Criar ou editar um item — página e não modal: muitos campos e listas que
 * crescem (docs/padroes-interface.md do NetScreen AI).
 *
 * Criar: só o Bruno. Editar: o Bruno e quem atualiza itens (David, Ana, Marco, Daniel).
 * Cliente e equipamento sugerem o que já está na base; um cliente novo entra na base.
 * Ao editar, as datas das etapas que já existem não mudam aqui: mudam no painel do
 * item, para ficar o histórico e a marca de prazo falhado.
 */

const EQUIPAMENTO_VAZIO = { qtd: 1, descricao: '', cabines: '', series: '', artigo: '' };
const MAX_OBS_FORM = 10000; // o mesmo limite do servidor (lib/itens.js)

// Os campos de encomenda e faturação do Excel da Ana, pela ordem do Excel (lib/itens.js aceita estes)
const CAMPOS_COMERCIAIS_FORM = ['proposta', 'guiaComercial', 'contratoRenting', 'notaEncomenda', 'pr', 'fp', 'faa',
  'envioAprovacao', 'dataAprovacao', 'envioFaturar', 'fns', 'tmi', 'conteudos', 'g4', 'nAT', 'fotos'];

/**
 * Um valor em euros escrito à portuguesa: "31.250,50", "31 250,5 €", "31250".
 * Devolve null se vazio, NaN se não for um número (e o formulário avisa).
 */
function lerValorEuros(txt) {
  let t = String(txt || '').replace(/€|\s/g, '');
  if (!t) return null;
  // "31,250.00" (à inglesa) seria lido como 31,25 € sem aviso: recusa e o formulário pede o formato português
  if (t.includes(',') && t.lastIndexOf('.') > t.lastIndexOf(',')) return NaN;
  if (t.startsWith('-')) return NaN; // um valor negativo não é um negócio
  if (t.includes(',')) t = t.replace(/\./g, '').replace(',', '.');
  else if (/^\d{1,3}(\.\d{3})+$/.test(t)) t = t.replace(/\./g, ''); // "31.250" = trinta e um mil
  return /^-?\d+(\.\d+)?$/.test(t) ? Number(t) : NaN;
}

/**
 * O cliente da base que corresponde a um nome (sem maiúsculas, acentos nem pontuação).
 * Com repetidos, fica o que tem nº — o do sistema de faturação.
 */
function clienteDaBase(clientes, nome) {
  const iguais = clientes.filter((c) => mesmoNome(c.nome, nome));
  return iguais.find((c) => c.numero != null) || iguais[0] || null;
}
function etapasParaFormulario(item) {
  return TIPOS_ETAPA.map((tipo) => {
    const e = item ? item.etapas.find((x) => x.tipo === tipo) : null;
    return {
      tipo,
      existente: !!e,
      aplicavel: e ? e.aplicavel : tipo !== 'aprovacao',
      data: e && e.prevista.data ? e.prevista.data : '',
      precisao: e ? e.prevista.precisao : 'dia',
      entregaTipo: (e && e.entregaTipo) || 'instalacao',
      // A aprovação é do comercial (por omissão, o Marco, que tem a maioria dos itens)
      responsavel: (e && e.responsavel) || RESPONSAVEL_POR_ETAPA[tipo] || (tipo === 'aprovacao' ? (item && item.comerciais[0]) || 'Marco Faria' : ''),
    };
  });
}

function CampoFormulario({ rotulo, ajuda, className = '', children }) {
  return (
    <label className={className}>
      <span className="mb-1.5 block text-sm font-medium">
        {rotulo} {ajuda && <span className="font-normal text-muted-foreground">{ajuda}</span>}
      </span>
      {children}
    </label>
  );
}

function ScreenItemForm({ numeroEditar }) {
  const { dados, utilizador, acoes, irPara } = useLista();
  const original = numeroEditar != null ? dados.itens.find((i) => i.numero === numeroEditar) : null;
  const editar = !!original;
  const proximo = Math.max.apply(null, dados.itens.map((i) => i.numero)) + 1;
  const comerciaisBase = dados.pessoas.filter((p) => p.comercial).map((p) => p.nome);

  const [numero, setNumero] = React.useState(String(original ? original.numero : proximo));
  const [cliente, setCliente] = React.useState(original ? original.cliente : '');
  const [comerciais, setComerciais] = React.useState(original ? original.comerciais : ['Marco Faria']);
  const [valor, setValor] = React.useState(original && original.valor != null ? fmtEuros(original.valor).replace(/\s*€$/, '') : '');
  const [tipoVenda, setTipoVenda] = React.useState((original && original.tipoVenda) || '');
  // Ao editar, um campo vazio fica vazio: antes o formulário punha ADJUDICADO / Por faturar e gravava-os sem ninguém pedir
  const [situacao, setSituacao] = React.useState(original ? original.situacao || '' : 'ADJUDICADO');
  const [faturacao, setFaturacao] = React.useState(original ? original.faturacao || '' : 'por_faturar');
  const [comercial, setComercial] = React.useState(() => Object.assign({}, (original && original.comercial) || {}));
  const [pendente, setPendente] = React.useState(original ? !!original.pendenteInstalacao : false);
  const [equipamentos, setEquipamentos] = React.useState(original && original.equipamentos.length
    ? original.equipamentos.map((q) => Object.assign({}, q, { series: q.series.join('\n'), artigo: q.artigo || '' }))
    : [Object.assign({}, EQUIPAMENTO_VAZIO)]);
  const [etapas, setEtapas] = React.useState(() => etapasParaFormulario(original));
  const [outras, setOutras] = React.useState([]);
  // As etapas extra que o item já tem: muda-se o nome, o responsável, ou tiram-se
  const [extras, setExtras] = React.useState(() => (original ? original.etapas
    .map((e, idx) => ({ idx, tipo: e.tipo, nome: e.nome || '', responsavel: e.responsavel || '', concluida: !!e.concluida, remover: false }))
    .filter((e) => e.tipo === 'outra') : []));
  const [obs, setObs] = React.useState(original ? original.obs || '' : '');
  const [chamada, setChamada] = React.useState(original ? !!original.chamadaAtencao : false);
  const [erro, setErro] = React.useState('');
  const [aGravar, setAGravar] = React.useState(false);

  const podeCriar = utilizador.perfil === 'admin';
  const podeEditar = podeCriar || utilizador.perfil === 'editor';
  // Um link para editar um item que não existe (antes abria o "Novo item")
  if (numeroEditar != null && !original) {
    return (
      <>
        <CabecalhoPagina titulo={`Editar item ${numeroEditar}`} />
        <p className="text-sm text-muted-foreground">O item {numeroEditar} não existe. <a href="#/resumo" className="text-foreground underline">Voltar ao resumo</a></p>
      </>
    );
  }
  if ((editar && !podeEditar) || (!editar && !podeCriar)) {
    return (
      <>
        <CabecalhoPagina titulo={editar ? `Editar item ${numeroEditar}` : 'Novo item'} />
        <p className="text-sm text-muted-foreground">
          {editar ? 'O teu perfil é só de consulta: não podes editar itens.' : 'Só o Bruno cria itens.'}
        </p>
      </>
    );
  }

  // O nº de cliente: enquanto o nome for o do item, fica o nº que o item já tinha (o nome do item e o da
  // base podem diferir — "Fujifilm" / "FIJIFILM"); só um nome novo vai procurar o nº à base.
  const mesmoClienteDoItem = editar && mesmoNome(cliente, original.cliente);
  const clienteBase = mesmoClienteDoItem ? null : clienteDaBase(dados.clientes, cliente);
  const clienteNumero = mesmoClienteDoItem ? (original.clienteNumero ?? null) : (clienteBase ? clienteBase.numero : null);
  const responsaveis = (atual) => dados.pessoas.filter((p) => p.perfil !== 'leitor' || p.nome === atual);
  const mudarLista = (setter) => (i, campo, v) => setter((l) => l.map((e, j) => (j === i ? Object.assign({}, e, { [campo]: v }) : e)));
  // Escolher um equipamento da base preenche a cabine habitual dele, se a linha ainda não tiver cabine
  const mudarEquip = (i, campo, v) => setEquipamentos((l) => l.map((e, j) => {
    if (j !== i) return e;
    const novo = Object.assign({}, e, { [campo]: v });
    if (campo === 'descricao' && !e.cabines.trim()) {
      const daBase = dados.equipamentos.find((b) => mesmoNome(b.descricao, v));
      if (daBase && daBase.cabine) novo.cabines = daBase.cabine;
    }
    // ...e o código de artigo, se a linha ainda não tiver
    if (campo === 'descricao' && !String(e.artigo || '').trim()) {
      const daBase = dados.equipamentos.find((b) => mesmoNome(b.descricao, v));
      if (daBase && daBase.artigo) novo.artigo = daBase.artigo;
    }
    return novo;
  }));
  // Escolher uma data numa etapa "por definir" passa-a a dia certo (como no modal): o que se vê é o que se grava
  const comData = (e, campo, v) => (campo === 'data' && v && e.precisao === 'desconhecida' ? { precisao: 'dia' } : {});
  const mudarEtapa = (i, campo, v) => setEtapas((l) => l.map((e, j) => (j === i ? Object.assign({}, e, { [campo]: v }, comData(e, campo, v)) : e)));
  const mudarOutra = (i, campo, v) => setOutras((l) => l.map((e, j) => (j === i ? Object.assign({}, e, { [campo]: v }, comData(e, campo, v)) : e)));
  const mudarExtra = mudarLista(setExtras);
  // Sem data, a etapa fica "por definir" (antes "Semana" sem data virava "por definir" sem aviso)
  const previstaApi = (aplicavel, data, precisao) => (aplicavel && data ? { data, precisao } : { data: null, precisao: 'desconhecida' });
  const alternarComercial = (nome) => setComerciais((l) => (l.includes(nome) ? l.filter((n) => n !== nome) : l.concat([nome])));

  async function guardar(ev) {
    ev.preventDefault();
    const n = Number(numero);
    if (!/^\d+$/.test(String(numero).trim()) || n <= 0 || n > 2147483647) { setErro('O nº do item é um número inteiro positivo (ex.: 944).'); return; }
    if (!cliente.trim()) { setErro('Indica o cliente.'); return; }
    const qtdMal = equipamentos.find((e) => e.descricao.trim() && !(/^\d+$/.test(String(e.qtd).trim()) && Number(e.qtd) >= 1));
    if (qtdMal) { setErro(`A quantidade de "${qtdMal.descricao.trim()}" tem de ser um número inteiro, 1 ou mais.`); return; }
    if (obs.length > MAX_OBS_FORM) { setErro(`As observações têm ${obs.length} caracteres; o máximo é ${MAX_OBS_FORM}.`); return; }
    if (!editar && dados.itens.some((i) => i.numero === n)) { setErro(`O item ${n} já existe. Escolhe outro número.`); return; }
    if (outras.some((o) => !o.nome.trim())) { setErro('Dá um nome a cada etapa extra.'); return; }
    const valorNum = lerValorEuros(valor);
    if (Number.isNaN(valorNum)) { setErro('O valor não é um número positivo. Escreve por exemplo 31250 ou 31.250,50.'); return; }
    setErro('');

    // Um cliente da base fica com o nome da base ("soltrafego" → "Soltráfego"), para os nomes ficarem uniformes
    const nomeCliente = !mesmoClienteDoItem && clienteBase ? clienteBase.nome : cliente.trim();
    const campos = {
      cliente: nomeCliente,
      clienteNumero,
      comerciais,
      valor: valorNum,
      tipoVenda: tipoVenda || null,
      situacao: situacao || null,
      faturacao: faturacao || null,
      obs: obs.trim(),
      equipamentos: equipamentos
        .filter((e) => e.descricao.trim())
        .map((e) => ({
          qtd: Number(e.qtd) || 1,
          descricao: e.descricao.trim(),
          cabines: e.cabines.trim(),
          artigo: e.artigo.trim() || undefined,
          series: e.series.split('\n').map((s) => s.trim()).filter(Boolean),
        })),
    };
    // O formato da API (api/itens.js): as datas vão como { data, precisao } e o servidor constrói o resto
    const outrasApi = outras.map((o) => ({ nome: o.nome.trim(), responsavel: o.responsavel, prevista: previstaApi(true, o.data, o.precisao) }));
    const etapasApi = etapas.map((e) => ({
      tipo: e.tipo, aplicavel: e.aplicavel, responsavel: e.responsavel, entregaTipo: e.entregaTipo,
      prevista: previstaApi(e.aplicavel, e.data, e.precisao),
    }));
    const extrasApi = extras
      .filter((x) => { const o = original.etapas[x.idx]; return x.remover || x.nome.trim() !== (o.nome || '') || x.responsavel !== (o.responsavel || ''); })
      .map((x) => ({ idx: x.idx, nome: x.nome.trim(), responsavel: x.responsavel, remover: x.remover }));
    if (extras.some((x) => !x.remover && !x.nome.trim())) { setErro('Dá um nome a cada etapa extra.'); return; }

    if (utilizador.perfil === 'admin') campos.chamadaAtencao = chamada;
    campos.pendenteInstalacao = pendente;
    if (editar) {
      campos.comercial = CAMPOS_COMERCIAIS_FORM.reduce((o, k) => Object.assign(o, { [k]: String(comercial[k] ?? '').trim() }), {});
    }

    setAGravar(true);
    const ok = editar
      ? await acoes.editarItem(n, { campos, etapas: etapasApi, outras: outrasApi, extras: extrasApi })
      : await acoes.criarItem(Object.assign({ numero: n }, campos, { etapas: etapasApi, outras: outrasApi }));
    setAGravar(false);
    if (ok) irPara('mes', n);
  }

  const titulo = editar ? `Editar item ${original.numero}` : 'Novo item';

  return (
    <form
      onSubmit={guardar}
      className="max-w-3xl"
      noValidate
      // Enter num campo não grava o item (criava-o só com o cliente); grava-se no botão
      onKeyDown={(ev) => { if (ev.key === 'Enter' && ev.target.tagName === 'INPUT') ev.preventDefault(); }}
    >
      <nav className="mb-3 text-sm text-muted-foreground" aria-label="Rasto">
        <a href="#/resumo" className="hover:text-foreground">Lista de Itens</a> / <span className="text-foreground">{titulo}</span>
      </nav>
      <CabecalhoPagina titulo={titulo}>
        {editar
          ? 'As alterações ficam no histórico do item, em teu nome, e são publicadas no grupo do Teams.'
          : 'Quando a Ana envia um negócio fechado. Ao criar, a equipa é avisada no grupo do Teams.'}
      </CabecalhoPagina>

      <datalist id="lista-clientes">{dados.clientes.map((c) => <option key={`${c.numero}-${c.nome}`} value={c.nome} />)}</datalist>
      <datalist id="lista-equipamentos">{dados.equipamentos.map((e) => <option key={e.descricao} value={e.descricao} />)}</datalist>
      <datalist id="lista-cabines">{dados.cabines.map((c) => <option key={c.id} value={c.descricao} />)}</datalist>

      <section className="border bg-card p-5">
        <h2 className="mb-4 text-sm font-semibold">Negócio</h2>
        <div className="grid gap-4 sm:grid-cols-2">
          <CampoFormulario rotulo="Nº do item">
            <input className="campo tabular-nums" type="number" value={numero} onChange={(e) => setNumero(e.target.value)} disabled={editar} required />
          </CampoFormulario>
          <CampoFormulario
            rotulo="Cliente"
            ajuda={!cliente.trim() ? '' : clienteNumero != null ? `(nº ${clienteNumero})`
              : mesmoClienteDoItem || clienteBase ? '(sem nº de cliente)'
              : utilizador.perfil === 'admin' ? '(novo — entra na base)' : '(não está na base)'}
          >
            <input className="campo" list="lista-clientes" value={cliente} onChange={(e) => setCliente(e.target.value)} placeholder="Procura na base ou escreve um novo" required autoFocus={!editar} />
          </CampoFormulario>
          <CampoFormulario rotulo="Valor" ajuda="(€, opcional)">
            <input className="campo tabular-nums" inputMode="decimal" value={valor} onChange={(e) => setValor(e.target.value)} placeholder="ex.: 13.170,00" />
          </CampoFormulario>
          <CampoFormulario rotulo="Tipo de venda">
            <select className="campo" value={tipoVenda} onChange={(e) => setTipoVenda(e.target.value)}>
              <option value="">—</option>
              {dados.listas.tipoVenda.map((t) => <option key={t}>{t}</option>)}
            </select>
          </CampoFormulario>
          <CampoFormulario rotulo="Situação">
            <select className="campo" value={situacao} onChange={(e) => setSituacao(e.target.value)}>
              <option value="">—</option>
              {dados.listas.situacao.map((t) => <option key={t}>{t}</option>)}
            </select>
          </CampoFormulario>
          <CampoFormulario rotulo="Faturação">
            <select className="campo" value={faturacao} onChange={(e) => setFaturacao(e.target.value)}>
              <option value="">—</option>
              <option value="por_faturar">Por faturar</option>
              <option value="faturado">Faturado</option>
            </select>
          </CampoFormulario>
        </div>
        <fieldset className="mt-4">
          <legend className="mb-1.5 text-sm font-medium">Comerciais</legend>
          <div className="flex flex-wrap gap-x-5 gap-y-2 text-sm">
            {Array.from(new Set(comerciaisBase.concat(comerciais))).map((nome) => (
              <label key={nome} className="flex items-center gap-2">
                <input type="checkbox" checked={comerciais.includes(nome)} onChange={() => alternarComercial(nome)} /> {nome}
              </label>
            ))}
          </div>
        </fieldset>
      </section>

      <section className="mt-4 border bg-card p-5">
        <h2 className="mb-4 text-sm font-semibold">Equipamento</h2>
        <div className="space-y-6">
          {equipamentos.map((e, i) => (
            <div key={i} className="grid gap-4 sm:grid-cols-[90px_1fr]">
              <CampoFormulario rotulo="Qtd.">
                <input className="campo tabular-nums" type="number" min="1" value={e.qtd} onChange={(ev) => mudarEquip(i, 'qtd', ev.target.value)} />
              </CampoFormulario>
              <CampoFormulario rotulo="Equipamento" ajuda="(da base, ou novo)">
                <input className="campo" list="lista-equipamentos" value={e.descricao} onChange={(ev) => mudarEquip(i, 'descricao', ev.target.value)} placeholder="Led Billboard 3.840 × 2.880mm PH6.67 HB" />
              </CampoFormulario>
              <CampoFormulario rotulo="Cabines" ajuda="(da base, ou nova)" className="sm:col-start-2">
                <input className="campo" list="lista-cabines" value={e.cabines} onChange={(ev) => mudarEquip(i, 'cabines', ev.target.value)} placeholder="960 × 960 mm" />
              </CampoFormulario>
              <CampoFormulario rotulo="Nºs de série" ajuda="(um por linha)" className="sm:col-start-2">
                <textarea className="campo" rows="2" value={e.series} onChange={(ev) => mudarEquip(i, 'series', ev.target.value)} placeholder="DG.NT.PL.OUT..." />
              </CampoFormulario>
              {equipamentos.length > 1 && (
                <button type="button" className={`${BOTAO_DISCRETO} justify-self-start sm:col-start-2`} onClick={() => setEquipamentos((l) => l.filter((x, j) => j !== i))}>
                  Tirar este equipamento
                </button>
              )}
            </div>
          ))}
        </div>
        <button type="button" className={`${BOTAO_SECUNDARIO} mt-4`} onClick={() => setEquipamentos((l) => l.concat([Object.assign({}, EQUIPAMENTO_VAZIO)]))}>
          <IconMais size={14} /> Adicionar outro equipamento
        </button>
      </section>

      <section className="mt-4 border bg-card p-5">
        <h2 className="text-sm font-semibold">Etapas</h2>
        <p className="mb-4 mt-1 text-sm text-muted-foreground">
          {editar
            ? 'Aqui escolhes que etapas se aplicam e quem é responsável. As datas mudam-se no painel do item, para ficar o histórico.'
            : 'Desmarca as que não se aplicam a este item. Sem data, fica "por definir (??)".'}
        </p>
        <div className="divide-y divide-[var(--border)]">
          {etapas.map((e, i) => (
            <div key={e.tipo} className="grid items-center gap-3 py-3 first:pt-0 sm:grid-cols-[200px_1fr_1fr_1fr]">
              <label className="flex items-center gap-2.5 text-sm font-medium">
                <input type="checkbox" checked={e.aplicavel} onChange={(ev) => mudarEtapa(i, 'aplicavel', ev.target.checked)} />
                {e.tipo === 'entrega' ? (
                  <select className="campo !w-auto" value={e.entregaTipo} onChange={(ev) => mudarEtapa(i, 'entregaTipo', ev.target.value)} aria-label="Tipo de entrega">
                    <option value="instalacao">Instalação no cliente</option>
                    <option value="recolha">Recolha pelo cliente</option>
                    <option value="envio">Envio ao cliente</option>
                  </select>
                ) : NOME_ETAPA[e.tipo]}
              </label>
              <select className="campo" value={e.responsavel} disabled={!e.aplicavel} onChange={(ev) => mudarEtapa(i, 'responsavel', ev.target.value)} aria-label={`Responsável por ${NOME_CURTO_ETAPA[e.tipo]}`}>
                {responsaveis(e.responsavel).map((p) => <option key={p.nome}>{p.nome}</option>)}
              </select>
              <input type="date" className="campo" value={e.data} disabled={!e.aplicavel || (editar && e.existente)} onChange={(ev) => mudarEtapa(i, 'data', ev.target.value)} aria-label={`Data prevista de ${NOME_CURTO_ETAPA[e.tipo]}`} />
              <select className="campo" value={e.precisao} disabled={!e.aplicavel || (editar && e.existente)} onChange={(ev) => mudarEtapa(i, 'precisao', ev.target.value)} aria-label={`Precisão da data de ${NOME_CURTO_ETAPA[e.tipo]}`}>
                {OPCOES_PRECISAO.map((o) => <option key={o.valor} value={o.valor}>{o.rotulo}</option>)}
              </select>
            </div>
          ))}
          {extras.map((x, i) => (
            <div key={`extra-${x.idx}`} className={`grid items-center gap-3 py-3 sm:grid-cols-[200px_1fr_1fr_1fr_auto] ${x.remover ? 'opacity-50' : ''}`}>
              <input className="campo" value={x.nome} disabled={x.remover} onChange={(ev) => mudarExtra(i, 'nome', ev.target.value)} aria-label={`Nome da etapa extra ${x.nome}`} />
              <select className="campo" value={x.responsavel} disabled={x.remover} onChange={(ev) => mudarExtra(i, 'responsavel', ev.target.value)} aria-label={`Responsável pela etapa ${x.nome}`}>
                {responsaveis(x.responsavel).map((p) => <option key={p.nome}>{p.nome}</option>)}
              </select>
              <span className="text-sm text-muted-foreground sm:col-span-2">
                {x.remover ? 'Vai ser retirada ao guardar.' : x.concluida ? 'Concluída. A data muda-se no painel do item.' : 'A data muda-se no painel do item.'}
              </span>
              <button type="button" className={BOTAO_DISCRETO} onClick={() => mudarExtra(i, 'remover', !x.remover)} aria-label={`${x.remover ? 'Manter' : 'Tirar'} a etapa ${x.nome}`}>
                {x.remover ? 'Manter' : 'Tirar'}
              </button>
            </div>
          ))}
          {outras.map((o, i) => (
            <div key={`outra-${i}`} className="grid items-center gap-3 py-3 sm:grid-cols-[200px_1fr_1fr_1fr_auto]">
              <input className="campo" value={o.nome} onChange={(ev) => mudarOutra(i, 'nome', ev.target.value)} placeholder="Nome da etapa" aria-label="Nome da etapa extra" />
              <select className="campo" value={o.responsavel} onChange={(ev) => mudarOutra(i, 'responsavel', ev.target.value)} aria-label="Responsável pela etapa extra">
                {responsaveis(o.responsavel).map((p) => <option key={p.nome}>{p.nome}</option>)}
              </select>
              <input type="date" className="campo" value={o.data} onChange={(ev) => mudarOutra(i, 'data', ev.target.value)} aria-label="Data prevista da etapa extra" />
              <select className="campo" value={o.precisao} onChange={(ev) => mudarOutra(i, 'precisao', ev.target.value)} aria-label="Precisão da data da etapa extra">
                {OPCOES_PRECISAO.map((op) => <option key={op.valor} value={op.valor}>{op.rotulo}</option>)}
              </select>
              <button type="button" className={BOTAO_DISCRETO} onClick={() => setOutras((l) => l.filter((x, j) => j !== i))} aria-label={`Tirar a etapa ${o.nome || 'extra'}`}>
                Tirar
              </button>
            </div>
          ))}
        </div>
        <button type="button" className={`${BOTAO_SECUNDARIO} mt-4`} onClick={() => setOutras((l) => l.concat([{ nome: '', responsavel: utilizador.nome, data: '', precisao: 'dia' }]))}>
          <IconMais size={14} /> Adicionar etapa
        </button>
        <p className="mt-2 text-xs text-muted-foreground">Para situações fora do habitual: fica a seguir à entrega, com nome e responsável próprios.</p>
      </section>

      {editar && (
        <section className="mt-4 border bg-card p-5">
          <h2 className="text-sm font-semibold">Encomenda e faturação</h2>
          <p className="mb-4 mt-1 text-sm text-muted-foreground">As colunas do Excel da Ana.</p>
          <div className="grid gap-4 sm:grid-cols-3">
            {CAMPOS_COMERCIAIS_FORM.map((k) => (
              <CampoFormulario key={k} rotulo={ROTULO_COMERCIAL[k] || k}>
                {/* As datas com calendário; um texto antigo que não seja data (ex. "SIM") continua editável */}
                <input
                  className="campo"
                  type={DATAS_COMERCIAIS.includes(k) && (!comercial[k] || /^\d{4}-\d{2}-\d{2}$/.test(comercial[k])) ? 'date' : 'text'}
                  value={comercial[k] ?? ''}
                  onChange={(ev) => setComercial((c) => Object.assign({}, c, { [k]: ev.target.value }))}
                />
              </CampoFormulario>
            ))}
          </div>
        </section>
      )}

      <section className="mt-4 border bg-card p-5">
        <label className="mb-4 flex items-center gap-2.5 text-sm">
          <input type="checkbox" checked={pendente} onChange={(e) => setPendente(e.target.checked)} />
          Pendente de instalação <span className="text-muted-foreground">(vendido, à espera do OK do cliente ou de condições)</span>
        </label>
        <CampoFormulario
          rotulo="Observações"
          ajuda={obs.length > MAX_OBS_FORM * 0.9 ? `(${obs.length} de ${MAX_OBS_FORM} caracteres)` : ''}
        >
          <textarea className="campo" rows="3" value={obs} maxLength={MAX_OBS_FORM} onChange={(e) => setObs(e.target.value)} />
        </CampoFormulario>
        <label className="mt-4 flex items-center gap-2.5 text-sm">
          <input type="checkbox" checked={chamada} onChange={(e) => setChamada(e.target.checked)} disabled={utilizador.perfil !== 'admin'} />
          Marcar como chamada de atenção {utilizador.perfil !== 'admin' && <span className="text-muted-foreground">(só o Bruno)</span>}
        </label>
      </section>

      <div className="mt-6 flex flex-wrap items-center justify-end gap-3">
        {erro && <p role="alert" className="mr-auto text-sm text-[hsl(var(--offline))]">{erro}</p>}
        <a href={editar ? `#/mes?item=${original.numero}` : '#/resumo'} className={BOTAO_SECUNDARIO}>Cancelar</a>
        <button type="submit" className={BOTAO_PRIMARIO} disabled={aGravar}>{aGravar ? 'A gravar…' : editar ? 'Guardar alterações' : 'Criar item e avisar a equipa'}</button>
      </div>
    </form>
  );
}
