/* ============================================================
   PCP — Forms part 2: confirm, row menu, scanner, detail, login
   (shares global scope with ui.jsx / forms.jsx)
   ============================================================ */

// ---------------- Row action menu (··· → Editar / Excluir) ----------------
function RowMenu({ items, up }) {
  const [open, setOpen] = useState(false);
  return (
    <span className="menu-wrap" onClick={(e) => e.stopPropagation()}>
      <IconBtn icon="more" onClick={() => setOpen((o) => !o)} title="Ações" active={open} />
      {open &&
      <>
          <div className="menu-scrim" onClick={() => setOpen(false)} />
          <div className={"menu" + (up ? " up" : "")}>
            {items.map((it, i) => it.sep ? <div key={i} className="menu-sep" /> :
          <div key={i} className={"menu-item" + (it.danger ? " danger" : "")} onClick={() => {setOpen(false);it.onClick();}}>
                <Icon name={it.icon} size={15} />{it.label}
              </div>
          )}
          </div>
        </>
      }
    </span>);

}

// ---------------- Confirm (delete / destructive) ----------------
function ConfirmDialog({ app, onClose, title, message, confirmLabel = "Excluir", icon = "trash", danger = true, onConfirm, successMsg }) {
  return (
    <div className="modal-scrim" onMouseDown={onClose}>
      <div className="modal sm" onMouseDown={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <span className={"m-ic" + (danger ? " danger" : "")}><Icon name={icon} size={18} /></span>
          <div className="grow"><h2>{title}</h2></div>
        </div>
        <div className="modal-body"><p className="confirm-msg" style={{ margin: 0 }}>{message}</p></div>
        <div className="modal-foot">
          <span className="spacer" />
          <Btn onClick={onClose}>Cancelar</Btn>
          <Btn variant={danger ? "danger" : "primary"} icon={danger ? "trash" : "check"}
          onClick={() => {onClose();onConfirm && onConfirm();if (successMsg) app.toast(successMsg, "ok");}}>{confirmLabel}</Btn>
        </div>
      </div>
    </div>);

}

// ---------------- Scanner (real webcam · getUserMedia + BarcodeDetector) ----------------
function ScannerModal({ app, onClose }) {
  const videoRef = useRef(null);
  const streamRef = useRef(null);
  const rafRef = useRef(null);
  const [status, setStatus] = useState("init"); // init · live · denied · error · nocam
  const [found, setFound] = useState(null);
  const [code, setCode] = useState("");
  const [manual, setManual] = useState("");
  const [nonce, setNonce] = useState(0);

  const stop = () => {
    if (rafRef.current) { cancelAnimationFrame(rafRef.current); rafRef.current = null; }
    if (streamRef.current) { streamRef.current.getTracks().forEach((t) => t.stop()); streamRef.current = null; }
  };
  const matchCode = (raw) => {
    const up = String(raw).trim().toUpperCase();
    if (!up) return null;
    const items = app.estoque;
    return items.find((e) => e.sku.toUpperCase() === up) || items.find((e) => up.includes(e.sku.toUpperCase())) ||
      items.find((e) => e.sku.toUpperCase().includes(up)) || items.find((e) => e.nome.toUpperCase().includes(up)) || null;
  };
  const handleCode = (raw, fromManual) => {
    setCode(raw);
    const it = matchCode(raw);
    if (it) { setFound(it); stop(); }
    else if (fromManual) app.toast("Nenhum item com código “" + raw + "”", "warn");
  };
  const rescan = () => { setFound(null); setCode(""); setManual(""); setNonce((n) => n + 1); };
  const simulate = () => {
    if (!app.estoque.length) { app.toast("Cadastre itens no estoque primeiro", "warn"); return; }
    const it = app.estoque[Math.floor(Math.random() * app.estoque.length)];
    setCode(it.sku); setFound(it); stop();
  };

  useEffect(() => {
    let cancelled = false, detector = null, watchdog = null;
    setStatus("init");
    async function start() {
      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { setStatus("nocam"); return; }
      // some sandboxed contexts neither resolve nor reject getUserMedia — fall back after 7s
      watchdog = setTimeout(() => { if (!cancelled && !streamRef.current) setStatus((s) => s === "init" ? "error" : s); }, 7000);
      try {
        const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: "environment" } }, audio: false });
        if (cancelled) { stream.getTracks().forEach((t) => t.stop()); return; }
        clearTimeout(watchdog);
        streamRef.current = stream;
        if (videoRef.current) { videoRef.current.srcObject = stream; try { await videoRef.current.play(); } catch (e) {} }
        if (!cancelled) setStatus("live");
        if ("BarcodeDetector" in window) {
          try { detector = new window.BarcodeDetector({ formats: ["qr_code", "code_128", "ean_13", "code_39", "ean_8", "upc_a", "itf", "codabar"] }); } catch (e) { detector = null; }
        }
        if (detector) {
          const loop = async () => {
            if (cancelled || !videoRef.current) return;
            try { const codes = await detector.detect(videoRef.current); if (codes && codes.length) { handleCode(codes[0].rawValue); return; } } catch (e) {}
            rafRef.current = requestAnimationFrame(loop);
          };
          rafRef.current = requestAnimationFrame(loop);
        }
      } catch (err) {
        clearTimeout(watchdog);
        if (!cancelled) setStatus(err && (err.name === "NotAllowedError" || err.name === "SecurityError" || err.name === "PermissionDeniedError") ? "denied" : "error");
      }
    }
    start();
    return () => { cancelled = true; clearTimeout(watchdog); stop(); };
  }, [nonce]);

  const hasDetector = typeof window !== "undefined" && "BarcodeDetector" in window;
  const statusNote = {
    init: "iniciando câmera…",
    live: hasDetector ? "aponte para o código de barras / QR" : "câmera ativa — leitura automática indisponível neste navegador",
    denied: "acesso à câmera negado",
    error: "não foi possível abrir a câmera",
    nocam: "nenhuma câmera disponível",
  }[status];

  const openItem = () => { onClose(); app.setRoute("estoque"); app.toast(found.sku + " localizado", "ok"); };

  return (
    <Modal size="md" icon="scan" title="Scanner de código de barras" sub={found ? "Item localizado" : "Câmera do dispositivo · funciona offline"} onClose={() => { stop(); onClose(); }}
      footer={<>
        {!found && <Btn size="sm" icon="zap" onClick={simulate}>Simular leitura</Btn>}
        {found && <Btn size="sm" icon="refresh" onClick={rescan}>Escanear outro</Btn>}
        <span className="spacer" />
        <Btn onClick={() => { stop(); onClose(); }}>Fechar</Btn>
        {found && <><Btn icon="arrowDown" onClick={() => { app.move(found.sku, -1); }}>Baixa</Btn><Btn variant="primary" icon="arrowUp" onClick={() => { app.move(found.sku, 1); }}>Entrada</Btn></>}
      </>}>
      <div className={"scanner-view" + (found ? " is-found" : "") + (status !== "live" ? " is-off" : "")}>
        <video ref={videoRef} className="scan-video" playsInline muted autoPlay />
        {status !== "live" && (
          <div className="scan-off">
            <Icon name={status === "denied" ? "wifiOff" : status === "init" ? "scan" : "alert"} size={26} />
            <div className="scan-off-t">{statusNote}</div>
            {(status === "denied" || status === "nocam" || status === "error") &&
              <div className="scan-off-s">Use a leitura manual abaixo ou toque em “Tentar de novo”.</div>}
            {status !== "init" && status !== "live" && <Btn size="sm" icon="refresh" onClick={rescan} style={{ marginTop: 12 }}>Tentar de novo</Btn>}
          </div>
        )}
        <div className="frame"><i></i><i></i></div>
        {status === "live" && !found && <div className="laser" />}
        <div className="hint">{found ? "" : status === "live" ? (code ? "lendo " + code + "…" : statusNote) : ""}</div>
      </div>

      {found ? (
        <div className="sumbox" style={{ marginTop: 16 }}>
          <div className="row gap12"><span className="badge ok dotted"><Icon name="check" size={12} /> Detectado</span><span className="sku">{found.sku}</span><span className="spacer" /><Btn size="sm" icon="eye" onClick={openItem}>Abrir no estoque</Btn></div>
          <div style={{ fontSize: 15, fontWeight: 600, marginTop: 8 }}>{found.nome}</div>
          <div className="srow" style={{ marginTop: 6 }}><span className="muted">Saldo atual</span><span className="v">{found.saldo} {found.un} · <Badge tone={found.status} dotted>{found.statusLabel || (found.status === "crit" ? "Zerado" : found.status === "warn" ? "Baixo" : "OK")}</Badge></span></div>
          <div className="help" style={{ marginTop: 10 }}>Use <b>Entrada</b> / <b>Baixa</b> no rodapé para ajustar o saldo direto da leitura.</div>
        </div>
      ) : (
        <div style={{ marginTop: 14 }}>
          <Field label="Leitura manual" help={hasDetector ? "digite o SKU ou nome se preferir não usar a câmera" : "este navegador não decodifica automático — digite o SKU"}>
            <div className="row gap8">
              <div className="fld-wrap" style={{ flex: 1 }}>
                <Icon name="qr" size={15} className="ico-in" />
                <input className="fld" value={manual} onChange={(e) => setManual(e.target.value)} placeholder="Ex.: PARA ou Parafuso M8"
                  onKeyDown={(e) => e.key === "Enter" && handleCode(manual, true)} />
              </div>
              <Btn icon="search" onClick={() => handleCode(manual, true)}>Buscar</Btn>
            </div>
          </Field>
        </div>
      )}
    </Modal>
  );
}

// ---------------- OP detail (etapas, consumo, finalizar) ----------------
function OPDetail({ app, onClose, op }) {
  const o = op || app.ops[0];
  if (!o) return null;
  // Etapas do produto (catálogo + horas + modo); apontamento real persiste em o.etapasFeitas
  const prod = app.produtos.find((p) => p.nome === o.produto);
  const etapasProduto = prod && Array.isArray(prod.etapas) ? prod.etapas : [];
  const etapasFeitas = o.etapasFeitas || {};
  // Consumo previsto = BOM × planej; consumido = BOM × prod
  const consumo = ((prod && prod.bom) || []).map((b) => {
    const it = app.estoque.find((x) => x.sku === b.sku) || {};
    const prev = (+b.qtd || 0) * (+o.planej || 0);
    const cons = (+b.qtd || 0) * (+o.prod || 0);
    return { sku: b.sku, ins: it.nome || b.sku, prev, cons, un: it.un || "" };
  });

  const toggleEtapaFeita = (nomeEtapa) => {
    const novaMap = { ...etapasFeitas };
    if (novaMap[nomeEtapa]) {
      delete novaMap[nomeEtapa];
    } else {
      const u = app.user || {};
      novaMap[nomeEtapa] = { ts: new Date().toISOString(), uid: u.uid || "", email: u.email || "" };
    }
    app.opsApi.update(o._id, { etapasFeitas: novaMap, etapa: nomeEtapa, status: o.status === "planejado" ? "producao" : o.status });
    if (app.logEvento) app.logEvento(novaMap[nomeEtapa] ? "concluir_etapa_op" : "reabrir_etapa_op", { tipo: "op", id: o.op }, { etapa: nomeEtapa });
  };
  const restante = o.planej - o.prod;
  const [qtdProduzida, setQtdProduzida] = useState(restante);
  const finalize = () => {
    const q = Math.max(0, Math.min(restante, +qtdProduzida || 0));
    const completa = (o.prod + q) >= o.planej;
    onClose();
    app.openModal("confirm", {
      title: completa ? `Finalizar ${o.op}?` : `Registrar produção de ${q} un em ${o.op}?`,
      icon: "checkCircle",
      danger: false,
      confirmLabel: completa ? "Finalizar OP" : "Registrar e atualizar",
      message: completa
        ? <>Baixa <b>{q} un de BOM</b> do estoque e marca a OP como concluída.</>
        : <>Registra <b>{q} un</b> produzidas e baixa a BOM correspondente. A OP continua em produção com {restante - q} un restantes.</>,
      onConfirm: () => { if (o._id) app.finalizarOP(o._id, { qtdReal: q }); },
    });
  };
  const cancelar = () => {
    onClose();
    app.openModal("confirm", {
      title: `Cancelar ${o.op}?`,
      message: o.prod > 0
        ? <>A OP será marcada como cancelada. As <b>{o.prod} un já consumidas</b> permanecem baixadas do estoque.</>
        : <>A OP será marcada como cancelada.</>,
      confirmLabel: "Cancelar OP",
      successMsg: `${o.op} cancelada`,
      onConfirm: () => { if (o._id) app.cancelarOP(o._id); },
    });
  };
  return (
    <Modal size="lg" icon="factory" title={o.op} sub={o.produto} onClose={onClose}
    footer={<>
      <Btn icon="printer" onClick={() => { app.toast("Gerando ficha de " + o.op + "…", "info"); PCPExport.printOP(o, app); }}>Imprimir OP</Btn>
      {o.status !== "cancelado" && o.status !== "finalizado" && <Btn icon="x" onClick={cancelar}>Cancelar OP</Btn>}
      <span className="spacer" />
      {restante > 0 && <div className="row gap8" style={{ alignItems: "center" }}>
        <span className="small muted">Qtd produzida:</span>
        <input className="fld right" type="number" min="0" max={restante} value={qtdProduzida} onChange={(e) => setQtdProduzida(e.target.value)} style={{ width: 80, height: 32 }} />
      </div>}
      {restante > 0 && <Btn variant="primary" icon="check" onClick={finalize}>{(+qtdProduzida || 0) >= restante ? "Finalizar" : "Registrar produção"}</Btn>}
    </>}>
      <div className="kv-big" style={{ marginBottom: 18 }}>
        <div className="b"><div className="l">Planejado</div><div className="v">{o.planej}</div></div>
        <div className="b"><div className="l">Produzido</div><div className="v" style={{ color: "var(--accent)" }}>{o.prod}</div></div>
        <div className="b"><div className="l">Restante</div><div className="v">{restante}</div></div>
      </div>
      <div className="row" style={{ justifyContent: "space-between", marginBottom: 14 }}>
        <span className="row gap8">
          {Array.isArray(o.itens) && o.itens.length > 1
            ? <Badge tone="info">{o.itens.length} pedidos</Badge>
            : (o.pedido && <Badge tone="info">OS {o.pedido}</Badge>)}
          <Badge tone={o.prio >= 7 ? "crit" : undefined} dotted><Icon name="zap" size={11} /> Prioridade {o.prio}</Badge>
        </span>
        {o.atrasada && <Badge tone="warn" dotted>Atrasada</Badge>}
      </div>

      {Array.isArray(o.itens) && o.itens.length > 0 && (
        <>
          <div className="form-sec">Pedidos cobertos</div>
          <div className="lines">
            <div className="lrow lhead" style={{ gridTemplateColumns: "100px 1fr 80px" }}>
              <div>OS</div><div>Cliente</div><div className="right">Qtd</div>
            </div>
            {o.itens.map((it, i) => (
              <div key={i} className="lrow" style={{ gridTemplateColumns: "100px 1fr 80px", padding: "9px 0" }}>
                <div style={{ padding: "0 12px", alignSelf: "center" }}><span className="mono small strong">{it.os}</span></div>
                <div style={{ padding: "0 12px", alignSelf: "center" }}>{it.cliente}</div>
                <div className="right mono strong" style={{ padding: "0 12px", alignSelf: "center" }}>{it.qtd}</div>
              </div>
            ))}
            <div className="lrow ltot" style={{ gridTemplateColumns: "100px 1fr 80px" }}>
              <div></div>
              <div className="right muted small" style={{ alignSelf: "center" }}>Total</div>
              <div className="right mono strong" style={{ alignSelf: "center", fontSize: 14, padding: "0 12px" }}>{o.itens.reduce((s, x) => s + (+x.qtd || 0), 0)}</div>
            </div>
          </div>
        </>
      )}

      <div className="form-sec">Etapas de execução</div>
      {etapasProduto.length === 0 ? (
        <div className="help"><Icon name="alert" size={12} /> Este produto não tem etapas cadastradas. Edite o produto para definir o roteiro.</div>
      ) : (
        <div className="checklist">
          {etapasProduto.map((e, i) => {
            const feito = etapasFeitas[e.nome];
            const tsLabel = feito ? new Date(feito.ts).toLocaleString("pt-BR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
            return (
              <div key={e.nome + i} className={"check-item" + (feito ? " done" : "")} onClick={() => toggleEtapaFeita(e.nome)}>
                <span className="order">{i + 1}</span>
                <span className="nm">{e.nome}</span>
                <span className="meta">{e.horas || 0}h · {e.modo === "terceirizado" ? "terceirizado" : "local"}{feito ? ` · ${tsLabel}${feito.email ? " por " + feito.email.split("@")[0] : ""}` : (e.nome === o.etapa ? " · em andamento" : "")}</span>
                <span className="box"><Icon name="check" size={13} /></span>
              </div>
            );
          })}
        </div>
      )}

      <div className="form-sec">Consumo de matéria-prima</div>
      {consumo.length === 0 ? (
        <div className="help">Este produto não tem BOM cadastrada — não há consumo previsto.</div>
      ) : (
        <div className="lines">
          <div className="lrow lhead" style={{ gridTemplateColumns: "1fr 90px 90px 90px" }}><div>Insumo</div><div className="right">Previsto</div><div className="right">Consumido</div><div className="right">A consumir</div></div>
          {consumo.map((c) =>
            <div key={c.sku} className="lrow" style={{ gridTemplateColumns: "1fr 90px 90px 90px", padding: "9px 0" }}>
              <div style={{ padding: "0 12px", alignSelf: "center", fontSize: 13 }}><span className="sku" style={{ marginRight: 6 }}>{c.sku}</span>{c.ins}</div>
              <div className="right muted" style={{ padding: "0 12px", alignSelf: "center" }}>{c.prev} {c.un}</div>
              <div className="right strong mono" style={{ padding: "0 12px", alignSelf: "center" }}>{c.cons} {c.un}</div>
              <div className="right mono" style={{ padding: "0 12px", alignSelf: "center", color: c.prev - c.cons > 0 ? "var(--muted)" : "var(--ok)" }}>{Math.max(0, c.prev - c.cons)} {c.un}</div>
            </div>
          )}
        </div>
      )}
    </Modal>);

}

// ---------------- Pedido detail (ações de fluxo) ----------------
function PedidoDetail({ app, onClose, pedido }) {
  const p = pedido || app.pedidos[0];
  if (!p) return null;
  const st = { aberto: "Em aberto", andamento: "Em andamento", concluido: "Concluído", cancelado: "Cancelado" }[p.status];
  const itens = app.normItens ? app.normItens(p) : (p.itens || [{ tipo: "produto", nome: p.produto, qtd: p.qtd, preco: p.qtd ? p.valor / p.qtd : 0 }]);
  return (
    <Modal size="lg" icon="fileText" title={"OS " + p.os} sub={p.cliente} onClose={onClose}
    footer={<>
      <Btn icon="printer" onClick={() => { app.toast("Gerando OS " + p.os + "…", "info"); PCPExport.printPedido(p, app); }}>Imprimir</Btn>
      <Btn icon="factory" onClick={() => {
        onClose();
        const itensProduto = itens.filter((it) => it.tipo === "produto");
        if (itensProduto.length === 0) { app.toast("Este pedido não tem linhas tipo Produto", "warn"); return; }
        if (itensProduto.length === 1) {
          const idx = itens.findIndex((it) => it === itensProduto[0]);
          app.openModal("novaOP", { fromPedido: { _pedidoId: p._id, _lineIdx: idx, produto: itensProduto[0].nome, qtd: itensProduto[0].qtd, os: p.os, prio: p.prio } });
        } else {
          app.openModal("novaOP", { fromPedido: { _pedidoId: p._id, os: p.os, prio: p.prio } });
        }
      }}>Gerar OP</Btn>
      <span className="spacer" />
      <Btn icon="truck" onClick={() => { if (p._id) app.moverPedidoStatus(p._id, "andamento"); app.toast("OS " + p.os + " em andamento", "ok"); }}>Expedir</Btn>
      <Btn variant="primary" icon="check" onClick={() => {onClose();app.openModal("confirm", { title: "Marcar OS " + p.os + " como entregue?", icon: "checkCircle", danger: false, confirmLabel: "Confirmar entrega", message: <>Registra a <b>receita</b> no financeiro e libera as reservas.</>, successMsg: "OS " + p.os + " entregue", onConfirm: () => { if (p._id) app.moverPedidoStatus(p._id, "concluido"); } });}}>Marcar entregue</Btn>
    </>}>
      <div className="row" style={{ justifyContent: "space-between", marginBottom: 16 }}>
        <Badge tone={p.status === "concluido" ? "ok" : p.status === "cancelado" ? "crit" : p.status === "andamento" ? "accent" : undefined} dotted>{st}</Badge>
        <span className="row gap8">
          <Badge dotted><Icon name="zap" size={11} /> Prioridade {p.prio}</Badge>
          <Badge tone={p.atrasado ? "warn" : undefined} dotted><Icon name="calendar" size={11} /> {p.entrega}</Badge>
        </span>
      </div>
      {p.alerta && <div className="sumbox" style={{ marginBottom: 16, borderColor: "var(--crit-tint)", background: "var(--crit-tint)" }}><div className="row gap8" style={{ color: "var(--crit)", fontWeight: 600, fontSize: 13 }}><Icon name="alert" size={15} />{p.alerta === "ruptura" ? "Ruptura de estoque prevista — insumos insuficientes para produzir." : p.alerta === "margem" ? "Margem negativa — preço abaixo do custo estimado." : "Entrega atrasada."}</div></div>}

      <div className="form-sec">Itens do pedido</div>
      <div className="lines">
        <div className="lrow lhead" style={{ gridTemplateColumns: "90px 1fr 70px 110px 110px" }}><div>Tipo</div><div>Item</div><div className="right">Qtd</div><div className="right">Preço un.</div><div className="right">Subtotal</div></div>
        {itens.map((it, i) => (
          <div key={i} className="lrow" style={{ gridTemplateColumns: "90px 1fr 70px 110px 110px" }}>
            <div style={{ padding: "11px 12px" }}><Badge tone={it.tipo === "estoque" ? "info" : "accent"} dotted>{it.tipo === "estoque" ? "Estoque" : "Produto"}</Badge></div>
            <div style={{ padding: "11px 12px" }}>{it.sku ? <span className="sku" style={{ marginRight: 6 }}>{it.sku}</span> : null}{it.nome}</div>
            <div className="right" style={{ padding: "11px 12px" }}>{it.qtd}</div>
            <div className="right mono" style={{ padding: "11px 12px" }}>{fmtBR(it.preco || 0)}</div>
            <div className="right mono strong" style={{ padding: "11px 12px" }}>{fmtBR((it.preco || 0) * (it.qtd || 0))}</div>
          </div>
        ))}
        <div className="lrow ltot" style={{ gridTemplateColumns: "90px 1fr 70px 110px 110px" }}>
          <div></div><div></div><div></div>
          <div className="right muted small" style={{ alignSelf: "center" }}>Total</div>
          <div className="right mono" style={{ alignSelf: "center", fontSize: 15 }}>{fmtBR(p.valor)}</div>
        </div>
      </div>
      <div className="field-grid c2" style={{ marginTop: 16 }}>
        <div className="sumbox"><div className="l small muted">Previsão de produção</div><div style={{ marginTop: 4, fontWeight: 600 }}>{p.atrasado ? "Reprogramar" : "Dentro do prazo"}</div></div>
        <div className="sumbox"><div className="l small muted">Observações</div><div style={{ marginTop: 4, color: "var(--muted)" }}>—</div></div>
      </div>
    </Modal>);

}

// ---------------- Login ----------------
function Login({ theme }) {
  const [email, setEmail] = useState("");
  const [pass, setPass] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [info, setInfo] = useState("");

  const submit = async () => {
    if (busy) return;
    setErr(""); setInfo("");
    if (!email || !pass) { setErr("Informe e-mail e senha."); return; }
    setBusy(true);
    try {
      await window.pcpAuth.signIn(email, pass);
      // onAuthStateChanged em App.jsx assume a partir daqui
    } catch (e) {
      setErr(e.message || "Falha ao entrar.");
      setBusy(false);
    }
  };

  const reset = async () => {
    if (busy) return;
    setErr(""); setInfo("");
    if (!email) { setErr("Digite seu e-mail para receber o link de redefinição."); return; }
    setBusy(true);
    try {
      await window.pcpAuth.sendReset(email);
      setInfo("Enviamos um link de redefinição para " + email + ".");
    } catch (e) {
      setErr(e.message || "Falha ao enviar redefinição.");
    }
    setBusy(false);
  };

  return (
    <div className="login">
      <div className="login-card">
        <div className="login-head">
          <div className="login-logo" style={{ width: "60px", height: "60px", margin: "0px 0px 5px" }}><Icon name="factory" size={24} /></div>
          <h1>Entrar no PCP</h1>
          <div className="lsub">Gestão de produção</div>
        </div>
        <Field label="E-mail">
          <div className="fld-wrap">
            <Icon name="users" size={15} className="ico-in" />
            <input className="fld" type="email" autoComplete="username" value={email} disabled={busy}
              onChange={(e) => setEmail(e.target.value)} placeholder="voce@empresa.com"
              onKeyDown={(e) => e.key === "Enter" && submit()} />
          </div>
        </Field>
        <Field label="Senha">
          <div className="fld-wrap">
            <input className="fld" type="password" autoComplete="current-password" value={pass} disabled={busy}
              onChange={(e) => setPass(e.target.value)} placeholder="••••••••"
              onKeyDown={(e) => e.key === "Enter" && submit()} />
          </div>
        </Field>
        {err && <div className="help" style={{ color: "var(--crit)", margin: "4px 0 6px" }}><Icon name="alert" size={12} /> {err}</div>}
        {info && <div className="help" style={{ color: "var(--ok)", margin: "4px 0 6px" }}><Icon name="check" size={12} /> {info}</div>}
        <div className="lrow">
          <span className="muted small">Acesso restrito · libere e-mails pelo Firebase Console</span>
          <span className="spacer" style={{ flex: 1 }} />
          <a style={{ color: "var(--accent)", cursor: busy ? "default" : "pointer", opacity: busy ? 0.5 : 1 }} onClick={reset}>Esqueci a senha</a>
        </div>
        <Btn variant="primary" size="lg" icon={busy ? "refresh" : "logout"} onClick={submit} disabled={busy} style={{ width: "100%" }}>
          {busy ? "Entrando…" : "Entrar"}
        </Btn>
      </div>
    </div>);

}

// ---------------- Importar relatório Shopee/ML (analytics) ----------------
function ImportRelatorioMarketplaceModal({ app, onClose, canal = "shopee" }) {
  const fileRef = useRef(null);
  const [fileName, setFileName] = useState("");
  const [erro, setErro] = useState("");
  const [resultado, setResultado] = useState(null); // {tipo, registros, vendasPorDia, preview}
  const canalLabel = canal === "shopee" ? "Shopee" : "Mercado Livre";

  const num = (s) => {
    if (typeof s === "number") return s;
    if (s == null || s === "") return 0;
    const cleaned = String(s).replace(/\./g, "").replace(",", ".").replace(/[^\d.\-]/g, "");
    return parseFloat(cleaned) || 0;
  };
  // converte "01/04/2026" ou "01/04/2026 14:00" → {data: "2026-04-01", hora: 14 ou null}
  const parseDataHora = (s) => {
    if (!s) return null;
    if (s instanceof Date) {
      const y = s.getFullYear(), m = String(s.getMonth() + 1).padStart(2, "0"), d = String(s.getDate()).padStart(2, "0");
      return { data: `${y}-${m}-${d}`, hora: s.getHours() || null };
    }
    const str = String(s).trim();
    const m = /^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:\s+(\d{1,2}):\d{2})?/.exec(str);
    if (!m) return null;
    const data = `${m[3]}-${String(+m[2]).padStart(2, "0")}-${String(+m[1]).padStart(2, "0")}`;
    return { data, hora: m[4] != null ? +m[4] : null };
  };

  const detectarTipo = (sheets) => {
    // shop-stats: tem aba "Pedido Feito" e "Produto Pago"
    if (sheets.includes("Pedido Feito")) return "shop_stats";
    // sales_overview: aba "Visão Geral das Vendas"
    if (sheets.some((n) => /vis(ã|a)o\s*geral.*vendas/i.test(n))) return "sales_overview";
    // productoverview: aba "overview"
    if (sheets.some((n) => /^overview$/i.test(n))) return "product_overview";
    return null;
  };

  const onFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!f) return;
    if (typeof XLSX === "undefined") { setErro("Biblioteca XLSX não carregou"); return; }
    setFileName(f.name); setErro(""); setResultado(null);
    try {
      const buf = await f.arrayBuffer();
      const wb = XLSX.read(buf, { type: "array", cellDates: true });
      const tipo = detectarTipo(wb.SheetNames);
      if (!tipo) { setErro("Não reconheci o formato. Aceita: shop stats, sales overview, product overview."); return; }

      const registros = []; // analytics
      const acumPorDia = {}; // {YYYY-MM-DD: vendas total}

      if (tipo === "shop_stats") {
        // Lê a aba "Pedido Feito" (mais completa) — pula totalizador (rows 0-2), header em row 3, dados em row 4+
        const sheet = wb.Sheets["Pedido Feito"];
        const data = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false, defval: "" });
        // header está em rows[3]
        for (let i = 4; i < data.length; i++) {
          const r = data[i];
          const dh = parseDataHora(r[0]); if (!dh) continue;
          const vendas = num(r[1]);
          const vendasSemDesc = num(r[2]);
          const pedidos = num(r[3]);
          const visitantes = num(r[6]);
          const cliques = num(r[5]);
          const conv = num(String(r[7] || "").replace("%", ""));
          const pedCanc = num(r[8]);
          const vendasCanc = num(r[9]);
          registros.push({
            canal, data: dh.data, hora: null, fonte: "shop_stats",
            vendas, vendasSemDesconto: vendasSemDesc, pedidos, visitantes, cliques, taxaConversao: conv,
            pedidosCancelados: pedCanc, vendasCanceladas: vendasCanc,
            importadoEm: new Date().toISOString(),
          });
          if (vendas > 0) acumPorDia[dh.data] = (acumPorDia[dh.data] || 0) + vendas;
        }
      } else if (tipo === "sales_overview") {
        const sheetName = wb.SheetNames.find((n) => /vis(ã|a)o\s*geral.*vendas/i.test(n));
        const sheet = wb.Sheets[sheetName];
        const data = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false, defval: "" });
        // pula totalizador (rows 0-2), header row 3, dados row 4+
        for (let i = 4; i < data.length; i++) {
          const r = data[i];
          const dh = parseDataHora(r[0]); if (!dh) continue;
          const visitantes = num(r[1]);
          const pedidos = num(r[4]);
          const vendas = num(r[5]);
          const taxa = num(String(r[6] || "").replace("%", ""));
          registros.push({
            canal, data: dh.data, hora: dh.hora, fonte: "sales_overview",
            visitantes, pedidos, vendas, taxaConversao: taxa,
            importadoEm: new Date().toISOString(),
          });
          if (vendas > 0) acumPorDia[dh.data] = (acumPorDia[dh.data] || 0) + vendas;
        }
      } else if (tipo === "product_overview") {
        const sheet = wb.Sheets[wb.SheetNames.find((n) => /^overview$/i.test(n))];
        const data = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false, defval: "" });
        for (let i = 1; i < data.length; i++) {
          const r = data[i];
          const dh = parseDataHora(r[0]); if (!dh) continue;
          const visitantes = num(r[1]);
          const visualizacoes = num(r[2]);
          const carrinho = num(r[9]);
          const pedidos = num(r[12]);
          const vendas = num(r[14]);
          registros.push({
            canal, data: dh.data, hora: dh.hora, fonte: "product_overview",
            visitantes, visualizacoes, addCarrinho: carrinho, pedidos, vendas,
            importadoEm: new Date().toISOString(),
          });
          if (vendas > 0) acumPorDia[dh.data] = (acumPorDia[dh.data] || 0) + vendas;
        }
      }

      const vendasPorDia = Object.entries(acumPorDia).map(([data, valor]) => ({ data, valor })).sort((a, b) => a.data.localeCompare(b.data));
      setResultado({ tipo, registros, vendasPorDia });
    } catch (err) {
      console.error(err); setErro("Falha ao processar: " + (err.message || err));
    }
  };

  const importar = (criarLancamentos) => {
    if (!resultado) return;
    const analyticsRes = app.upsertAnalytics(resultado.registros);
    let financRes = { adicionados: 0, atualizados: 0 };
    if (criarLancamentos) {
      financRes = app.importarVendasCanalComoLancamentos(canal, resultado.vendasPorDia);
    }
    if (app.logEvento) app.logEvento("importar_relatorio_canal", { tipo: "analytics", id: canal }, { fonte: resultado.tipo, arquivo: fileName, analytics: analyticsRes, financeiro: financRes });
    onClose();
    const partes = [
      `${analyticsRes.adicionados + analyticsRes.atualizados} registros de analytics`,
    ];
    if (criarLancamentos) partes.push(`${financRes.adicionados} lançamentos`);
    app.toast(`${canalLabel} importado`, "ok", { sub: partes.join(" · ") });
  };

  return (
    <Modal size="lg" icon="upload" title={"Importar relatório " + canalLabel} sub="Shop Stats, Sales Overview ou Product Overview" onClose={onClose}
      footer={<>
        <span className="hintnote"><Icon name="fileText" size={14} /> {resultado ? `${resultado.registros.length} registros` : "nenhum arquivo"}</span>
        <span className="spacer" />
        <Btn onClick={onClose}>Cancelar</Btn>
        <Btn icon="check" disabled={!resultado} onClick={() => importar(false)}>Só analytics</Btn>
        <Btn variant="primary" icon="check" disabled={!resultado || resultado.vendasPorDia.length === 0} onClick={() => importar(true)}>Analytics + Financeiro</Btn>
      </>}>
      <input ref={fileRef} type="file" accept=".xlsx,.xls,.csv" style={{ display: "none" }} onChange={onFile} />
      {!resultado ? (
        <div className="upzone" style={{ padding: 34, cursor: "pointer" }} onClick={() => fileRef.current && fileRef.current.click()}>
          <div className="uz-ico"><Icon name="upload" size={20} /></div>
          <div className="uz-t">Clique para selecionar o relatório XLSX da {canalLabel}</div>
          <div className="uz-s">Aceita Shop Stats, Sales Overview, Product Overview</div>
          {erro && <div className="help" style={{ color: "var(--crit)", marginTop: 10 }}><Icon name="alert" size={12} /> {erro}</div>}
        </div>
      ) : (
        <>
          <div className="row" style={{ justifyContent: "space-between", marginBottom: 12 }}>
            <span className="row gap8"><Icon name="fileText" size={16} style={{ color: "var(--ok)" }} /><b>{fileName}</b> <span className="muted small">· {resultado.tipo}</span></span>
            <Btn size="sm" icon="x" onClick={() => { setResultado(null); setFileName(""); }}>Trocar</Btn>
          </div>

          <div className="metrics" style={{ gridTemplateColumns: "repeat(3, 1fr)", marginBottom: 14 }}>
            <MetricCard icon="list" label="Registros" value={resultado.registros.length} />
            <MetricCard icon="dollar" label="Vendas total" value={DB.BRL(resultado.vendasPorDia.reduce((s, x) => s + x.valor, 0)).replace("R$ ", "R$ ")} state="ok" />
            <MetricCard icon="calendar" label="Dias" value={resultado.vendasPorDia.length} />
          </div>

          {resultado.vendasPorDia.length > 0 && (
            <>
              <div className="form-sec">Vendas por dia (lançamentos a criar)</div>
              <div className="lines" style={{ maxHeight: 220, overflowY: "auto" }}>
                <div className="lrow lhead" style={{ gridTemplateColumns: "150px 1fr 130px" }}><div>Data</div><div>Descrição</div><div className="right">Valor</div></div>
                {resultado.vendasPorDia.map((v) => (
                  <div key={v.data} className="lrow" style={{ gridTemplateColumns: "150px 1fr 130px", padding: "8px 0" }}>
                    <div style={{ padding: "0 12px", alignSelf: "center" }}><span className="mono small">{v.data}</span></div>
                    <div style={{ padding: "0 12px", alignSelf: "center" }} className="small">Vendas {canalLabel}</div>
                    <div className="right mono strong" style={{ padding: "0 12px", alignSelf: "center" }}>{DB.BRL(v.valor).replace("R$ ", "R$ ")}</div>
                  </div>
                ))}
              </div>
              <div className="help" style={{ marginTop: 10 }}><Icon name="check" size={12} style={{ color: "var(--ok)" }} /> Importar com financeiro evita duplicar — se já existe lançamento da mesma data + canal, atualiza o valor.</div>
            </>
          )}
        </>
      )}
    </Modal>
  );
}

Object.assign(window, { RowMenu, ConfirmDialog, ScannerModal, OPDetail, PedidoDetail, Login, NotificationsBtn, ImportRelatorioMarketplaceModal });
// extend MODALS registry
MODALS.confirm = ConfirmDialog;
MODALS.scanner = ScannerModal;
MODALS.opDetail = OPDetail;
MODALS.pedidoDetail = PedidoDetail;
MODALS.importar = ImportModal;
MODALS.importarRelatorioCanal = ImportRelatorioMarketplaceModal;
MODALS.exportar = ExportModal;
MODALS.filtros = FiltrosModal;
MODALS.editarPerfil = EditarPerfilModal;
MODALS.novaNota = NovaNotaForm;
MODALS.novaEmpresa = NovaEmpresaForm;

// ---------------- Importar planilha ----------------
const IMPORT_META = {
  estoque:  { label: "itens de estoque", cols: ["SKU", "Nome", "Unidade", "Saldo", "Mínimo", "Preço"], rows: [["ITEM01", "Exemplo de item 1", "un", "0", "10", "0,00"], ["ITEM02", "Exemplo de item 2", "kg", "0", "5", "0,00"]] },
  pedidos:  { label: "pedidos", cols: ["OS", "Cliente", "Produto", "Qtd", "Entrega"], rows: [["100001", "Nome do cliente", "Nome do produto", "1", "2026-01-31"], ["100002", "Outro cliente", "Outro produto", "2", "2026-02-15"]] },
  clientes: { label: "clientes", cols: ["Nome", "CNPJ/CPF", "Cidade", "Telefone"], rows: [["Cliente Exemplo Ltda", "00.000.000/0000-00", "Cidade", "(00) 00000-0000"], ["Outro Cliente", "000.000.000-00", "Cidade", "(00) 00000-0000"]] },
};
window.IMPORT_META = IMPORT_META;
function ImportModal({ app, onClose, entity = "estoque" }) {
  const meta = IMPORT_META[entity] || IMPORT_META.estoque;
  const fileRef = useRef(null);
  const [fileName, setFileName] = useState("");
  const [headers, setHeaders] = useState([]);
  const [rows, setRows] = useState([]);
  const [erro, setErro] = useState("");
  const num = (s) => {
    if (typeof s === "number") return s;
    return parseFloat(String(s || "").replace(/\./g, "").replace(",", ".")) || 0;
  };

  // mapeamento: para cada coluna esperada, qual coluna do arquivo casa
  // tenta auto-match por nome
  const [mapeamento, setMapeamento] = useState({});
  useEffect(() => {
    if (headers.length === 0) return;
    const m = {};
    meta.cols.forEach((c) => {
      const norm = (s) => String(s || "").toLowerCase().normalize("NFD").replace(/[^a-z0-9]/g, "");
      const target = norm(c);
      const idx = headers.findIndex((h) => norm(h) === target);
      if (idx >= 0) m[c] = idx;
    });
    setMapeamento(m);
  }, [headers]);

  const onFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!f) return;
    if (typeof XLSX === "undefined") { setErro("Biblioteca XLSX não carregou"); return; }
    setFileName(f.name); setErro("");
    try {
      const buf = await f.arrayBuffer();
      const wb = XLSX.read(buf, { type: "array", cellDates: true });
      const sheet = wb.Sheets[wb.SheetNames[0]];
      const data = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false, defval: "" });
      if (!data.length) { setErro("Planilha vazia."); return; }
      const hdr = data[0].map((x) => String(x || "").trim());
      const body = data.slice(1).filter((r) => r.some((c) => String(c || "").trim() !== ""));
      setHeaders(hdr); setRows(body);
    } catch (err) {
      console.error(err); setErro("Falha ao ler a planilha: " + (err.message || err));
    }
  };

  const pickByMap = (row, col) => {
    const idx = mapeamento[col];
    return (idx != null && idx >= 0) ? row[idx] : "";
  };

  const apply = () => {
    let n = 0;
    rows.forEach((r) => {
      if (entity === "estoque") {
        const nome = String(pickByMap(r, "Nome") || "").trim();
        if (!nome) return;
        const sku = String(pickByMap(r, "SKU") || "").trim() || nome.replace(/[^a-zA-Z]/g, "").slice(0, 4).toUpperCase() || "ITEM";
        app.addItem({
          sku, nome, un: String(pickByMap(r, "Unidade") || "un").trim() || "un",
          saldo: num(pickByMap(r, "Saldo")), min: num(pickByMap(r, "Mínimo")),
          preco: num(pickByMap(r, "Preço")), reservado: 0, forn: "—", lead: 0,
        });
        n++;
      } else if (entity === "pedidos") {
        const cliente = String(pickByMap(r, "Cliente") || "").trim();
        if (!cliente) return;
        const os = String(pickByMap(r, "OS") || "").trim() || String(Math.floor(100000 + Math.random() * 899999));
        const produto = String(pickByMap(r, "Produto") || "").trim();
        const qtd = num(pickByMap(r, "Qtd")) || 1;
        const entrega = String(pickByMap(r, "Entrega") || "—").trim();
        app.criarPedido({ os, cliente, produto, qtd, valor: 0, prio: 5, entrega });
        n++;
      } else if (entity === "clientes") {
        const nome = String(pickByMap(r, "Nome") || "").trim();
        if (!nome) return;
        app.clientesApi.add({
          nome,
          doc: String(pickByMap(r, "CNPJ/CPF") || "").trim(),
          cidade: String(pickByMap(r, "Cidade") || "").trim(),
          uf: "",
          tel: String(pickByMap(r, "Telefone") || "").trim(),
          email: "", pedidos: 0, total: 0, ultimo: "—",
        }, true);
        n++;
      }
    });
    if (app.logEvento) app.logEvento("importar_planilha", { tipo: entity, id: fileName }, { linhas: n });
    onClose();
    app.toast(`${n} ${meta.label} importados`, "ok", { sub: fileName });
  };

  const hasFile = rows.length > 0;
  const todasMapeadas = meta.cols.every((c) => mapeamento[c] != null);
  return (
    <Modal size="lg" icon="upload" title={"Importar " + meta.label} sub="Planilha XLSX ou CSV" onClose={onClose}
      footer={<>
        <span className="hintnote"><Icon name="fileText" size={14} /> {hasFile ? `${rows.length} linhas detectadas` : "nenhum arquivo"}</span>
        <span className="spacer" />
        <Btn onClick={onClose}>Cancelar</Btn>
        <Btn variant="primary" icon="check" disabled={!hasFile || !todasMapeadas} onClick={apply}>Importar {rows.length || ""}</Btn>
      </>}>
      <input ref={fileRef} type="file" accept=".xlsx,.xls,.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,text/csv" style={{ display: "none" }} onChange={onFile} />
      {!hasFile ? (
        <div className="upzone" style={{ padding: 34, cursor: "pointer" }} onClick={() => fileRef.current && fileRef.current.click()}>
          <div className="uz-ico"><Icon name="upload" size={20} /></div>
          <div className="uz-t">Clique para selecionar a planilha</div>
          <div className="uz-s">XLSX, XLS ou CSV · 1ª linha = cabeçalho</div>
          {erro && <div className="help" style={{ color: "var(--crit)", marginTop: 10 }}><Icon name="alert" size={12} /> {erro}</div>}
        </div>
      ) : (
        <>
          <div className="row" style={{ justifyContent: "space-between", marginBottom: 10 }}>
            <span className="row gap8"><Icon name="fileText" size={16} style={{ color: "var(--ok)" }} /><b>{fileName}</b> <span className="muted small">· {rows.length} linhas</span></span>
            <Btn size="sm" icon="x" onClick={() => { setRows([]); setHeaders([]); setFileName(""); }}>Trocar</Btn>
          </div>
          <div className="form-sec">Mapeamento de colunas</div>
          <div className="field-grid c2" style={{ marginBottom: 14 }}>
            {meta.cols.map((c) => (
              <Field key={c} label={c} req>
                <select className="fld" value={mapeamento[c] != null ? mapeamento[c] : ""} onChange={(e) => setMapeamento({ ...mapeamento, [c]: e.target.value === "" ? null : +e.target.value })}>
                  <option value="">— escolha a coluna —</option>
                  {headers.map((h, i) => <option key={i} value={i}>{h || `(col ${i + 1})`}</option>)}
                </select>
              </Field>
            ))}
          </div>
          <div className="form-sec">Pré-visualização (5 primeiras)</div>
          <div className="lines"><div className="tbl-wrap"><table className="tbl">
            <thead><tr>{meta.cols.map((c) => <th key={c}>{c}</th>)}</tr></thead>
            <tbody>
              {rows.slice(0, 5).map((r, i) => (
                <tr key={i}>{meta.cols.map((c) => <td key={c}>{String(pickByMap(r, c) || "—")}</td>)}</tr>
              ))}
            </tbody>
          </table></div></div>
          {!todasMapeadas && <div className="help" style={{ marginTop: 10, color: "var(--warn)" }}><Icon name="alert" size={12} /> Mapeie todas as colunas para prosseguir.</div>}
        </>
      )}
    </Modal>
  );
}

// ---------------- Exportar ----------------
function ExportModal({ app, onClose, entity = "dados" }) {
  const [fmt, setFmt] = useState("xlsx");
  const [scope, setScope] = useState("tudo");
  const preview = PCPExport.data(entity, app);
  const run = () => {
    onClose();
    PCPExport.run(entity, fmt, app);
    app.toast(`${preview.title} exportado (${fmt.toUpperCase()})`, "ok", { sub: fmt === "pdf" ? "abrindo impressão…" : preview.rows.length + " linhas · download iniciado", icon: "download" });
  };
  return (
    <Modal size="sm" icon="download" title={"Exportar " + preview.title.toLowerCase()} onClose={onClose}
      footer={<><span className="hintnote"><Icon name="fileText" size={14} /> {preview.rows.length} registros</span><span className="spacer" /><Btn onClick={onClose}>Cancelar</Btn><Btn variant="primary" icon="download" onClick={run}>Exportar</Btn></>}>
      <Field label="Formato">
        <Choice value={fmt} onChange={setFmt} options={[{ v: "xlsx", l: "Excel" }, { v: "csv", l: "CSV" }, { v: "pdf", l: "PDF / imprimir" }]} />
      </Field>
      <Field label="Abrangência">
        <Choice value={scope} onChange={setScope} options={[{ v: "tudo", l: "Tudo" }, { v: "filtrados", l: "Somente filtrados" }]} />
      </Field>
      <div className="sumbox" style={{ marginTop: 4 }}>
        <div className="srow"><span className="muted">Conteúdo</span><span className="v">{preview.title}</span></div>
        <div className="srow"><span className="muted">Colunas</span><span className="v">{preview.columns.length}</span></div>
        <div className="srow"><span className="muted">Registros</span><span className="v">{preview.rows.length}</span></div>
      </div>
      <div className="help" style={{ marginTop: 10 }}><Icon name="check" size={12} style={{ color: "var(--ok)" }} /> {fmt === "pdf" ? "Abre um documento limpo pronto para imprimir ou salvar em PDF." : "Gera o arquivo e baixa direto no seu computador — funciona offline."}</div>
    </Modal>
  );
}

// ---------------- Filtros avançados ----------------
function FiltrosModal({ app, onClose, kind = "geral" }) {
  return (
    <Modal size="sm" icon="filter" title="Filtros avançados" onClose={onClose}
      footer={<><Btn onClick={() => { onClose(); app.toast("Filtros limpos", "info"); }}>Limpar</Btn><span className="spacer" /><Btn variant="primary" icon="check" onClick={() => { onClose(); app.toast("Filtros aplicados", "ok"); }}>Aplicar</Btn></>}>
      <Field label="Período">
        <select className="fld"><option>Últimos 30 dias</option><option>Este mês</option><option>Mês passado</option><option>Personalizado…</option></select>
      </Field>
      {kind === "pedidos" && <Field label="Prioridade mínima"><select className="fld"><option>Qualquer</option><option>5 ou mais</option><option>7 ou mais (urgente)</option></select></Field>}
      <Field label="Ordenar por">
        <select className="fld"><option>Mais recentes</option><option>Maior valor</option><option>Vencimento próximo</option></select>
      </Field>
      <Field label="Mostrar apenas">
        <Choice value="todos" onChange={() => {}} options={[{ v: "todos", l: "Todos" }, { v: "alerta", l: "Com alerta" }]} />
      </Field>
    </Modal>
  );
}

// ---------------- Editar perfil ----------------
function EditarPerfilModal({ app, onClose }) {
  const u = app.user || {};
  const nomeInicial = u.name && u.name !== u.email ? u.name : "";
  const emailInicial = u.email || "";
  const iniciais = (nomeInicial || emailInicial || "?").trim().split(/\s+/).map((p) => p[0]).slice(0, 2).join("").toUpperCase();
  return (
    <Modal size="sm" icon="users" title="Editar perfil" onClose={onClose}
      footer={<><span className="spacer" /><Btn onClick={onClose}>Cancelar</Btn><Btn variant="primary" icon="check" onClick={() => { onClose(); app.toast("Perfil atualizado", "ok"); }}>Salvar</Btn></>}>
      <div className="row gap12" style={{ marginBottom: 16 }}>
        <span className="avatar" style={{ width: 52, height: 52, fontSize: 17 }}>{iniciais}</span>
        <Btn size="sm" icon="image">Trocar foto</Btn>
      </div>
      <Field label="Nome"><input className="fld" defaultValue={nomeInicial} placeholder="Seu nome" /></Field>
      <Field label="E-mail"><input className="fld" type="email" defaultValue={emailInicial} readOnly /></Field>
      <Field label="Cargo"><input className="fld" placeholder="Ex.: Gerente" /></Field>
    </Modal>
  );
}

// ---------------- Nova nota fiscal ----------------
function NovaNotaForm({ app, onClose }) {
  const [num, setNum] = useState("");
  const [forn, setForn] = useState("");
  const [emissao, setEmissao] = useState("");
  const [valor, setValor] = useState("");
  const [compra, setCompra] = useState("");
  const [file, setFile] = useState(null);
  const fileRef = useRef(null);
  const onFile = (ev) => { const f = ev.target.files && ev.target.files[0]; if (!f) return; setFile({ url: URL.createObjectURL(f), name: f.name, type: f.type }); };
  const fornecedores = [...new Set(app.estoque.map((e) => e.forn).filter((f) => f && f !== "\u2014"))];
  const submit = () => {
    if (!forn) return app.toast("Informe o fornecedor", "crit");
    const numero = num || String(8400 + Math.floor(Math.random() * 99)).padStart(6, "0");
    const dataBR = emissao && /^\d{4}-/.test(emissao)
      ? new Date(emissao + "T00:00").toLocaleDateString("pt-BR", { day: "2-digit", month: "short" }).replace(".", "")
      : (emissao || new Date().toLocaleDateString("pt-BR", { day: "2-digit", month: "short" }).replace(".", ""));
    app.notasApi.add({ num: numero, forn, emissao: dataBR, valor: +valor || 0, compra: compra || "\u2014", anexo: !!file, anexoUrl: file ? file.url : undefined, anexoName: file ? file.name : undefined, anexoType: file ? file.type : undefined }, true);
    onClose(); app.toast("NF " + numero + " cadastrada", "ok", { sub: forn });
  };
  return (
    <Modal size="md" icon="receipt" title="Nova nota fiscal" sub="Documento de entrada" onClose={onClose}
      footer={<><span className="spacer" /><Btn onClick={onClose}>Cancelar</Btn><Btn variant="primary" icon="check" onClick={submit}>Salvar nota</Btn></>}>
      <div className="field-grid c2">
        <Field label="Número da nota" help="em branco = gera automático"><input className="fld" autoFocus value={num} onChange={(e) => setNum(e.target.value)} placeholder="008422" /></Field>
        <Field label="Emissão"><div className="fld-wrap"><Icon name="calendar" size={15} className="ico-in" /><input className="fld" type="date" value={emissao} onChange={(e) => setEmissao(e.target.value)} /></div></Field>
      </div>
      <Field label="Fornecedor" req>
        <input className="fld" value={forn} onChange={(e) => setForn(e.target.value)} placeholder="Ex.: Aços Sul" list="forn-list" />
        <datalist id="forn-list">{fornecedores.map((f) => <option key={f} value={f} />)}</datalist>
      </Field>
      <div className="field-grid c2">
        <Field label="Valor total" req><div className="fld-wrap"><span className="pre">R$</span><input className="fld" type="number" value={valor} onChange={(e) => setValor(e.target.value)} placeholder="0,00" /></div></Field>
        <Field label="Compra vinculada" opt>
          <select className="fld" value={compra} onChange={(e) => setCompra(e.target.value)}>
            <option value="">Nenhuma</option>
            {app.compras.map((c) => <option key={c._id} value={c.sku}>{c.sku} — {c.item}</option>)}
          </select>
        </Field>
      </div>
      <Field label="Anexar documento" opt>
        <input ref={fileRef} type="file" accept="application/pdf,image/*" style={{ display: "none" }} onChange={onFile} />
        <div className="upzone" onClick={() => fileRef.current && fileRef.current.click()} style={file ? { borderColor: "var(--ok)", background: "var(--ok-tint)" } : undefined}>
          <div className="uz-ico"><Icon name={file ? "check" : "paperclip"} size={18} /></div>
          <div className="uz-t">{file ? file.name : "Anexar PDF ou foto da NF"}</div>
          <div className="uz-s">{file ? "documento pronto \u2014 clique em salvar" : "fica vinculada \u00e0 compra e ao estoque"}</div>
        </div>
      </Field>
    </Modal>
  );
}

// ---------------- Nova empresa (workspace) ----------------
function NovaEmpresaForm({ app, onClose }) {
  const [name, setName] = useState("");
  const [cidade, setCidade] = useState("");
  const [uf, setUf] = useState("RS");
  const logo = (name.trim().split(/\s+/).map((w) => w[0]).join("").slice(0, 2).toUpperCase()) || "\u00b7\u00b7";
  const submit = () => {
    if (!name) return app.toast("Informe o nome da empresa", "crit");
    const sub = cidade ? cidade + " \u00b7 " + uf : uf;
    app.addWorkspace({ name, sub, logo });
    onClose();
  };
  return (
    <Modal size="sm" icon="building" title="Adicionar empresa" sub="Novo workspace" onClose={onClose}
      footer={<><span className="hintnote"><span className="ws-logo" style={{ width: 22, height: 22, fontSize: 9 }}>{logo}</span> logo gerada</span><span className="spacer" /><Btn onClick={onClose}>Cancelar</Btn><Btn variant="primary" icon="check" onClick={submit}>Adicionar</Btn></>}>
      <Field label="Razão social / nome" req><input className="fld" autoFocus value={name} onChange={(e) => setName(e.target.value)} placeholder="Ex.: Serralheria Andrade" /></Field>
      <div className="field-grid c2">
        <Field label="Cidade"><input className="fld" value={cidade} onChange={(e) => setCidade(e.target.value)} placeholder="Caxias do Sul" /></Field>
        <Field label="UF"><input className="fld" maxLength="2" value={uf} onChange={(e) => setUf(e.target.value.toUpperCase())} placeholder="RS" /></Field>
      </div>
      <div className="help"><Icon name="check" size={12} style={{ color: "var(--ok)" }} /> A empresa fica disponível no seletor da barra lateral. Você pode alternar entre elas a qualquer momento.</div>
    </Modal>
  );
}

// ---------------- Notificações (sino) ----------------
// Constrói lista de notificações a partir do estado real do app
function buildNotifs(app) {
  if (!app) return [];
  const list = [];
  (app.estoque || []).forEach((e) => {
    if (e.status === "crit") list.push({ id: `estoque-crit-${e.sku}`, ico: "alert", tone: "crit", t: `${e.nome} zerou no estoque`, s: "Estoque", route: "estoque" });
  });
  (app.pedidos || []).forEach((p) => {
    if (p.atrasado && p.status !== "concluido" && p.status !== "cancelado") {
      list.push({ id: `pedido-atraso-${p.os}`, ico: "clock", tone: "warn", t: `OS ${p.os} está atrasada`, s: "Pedidos", route: "pedidos" });
    }
  });
  (app.compras || []).forEach((c) => {
    if (c.status === "sugerida") list.push({ id: `compra-sug-${c._id}`, ico: "cart", tone: "warn", t: `Sugestão de compra: ${c.item}`, s: "Compras", route: "compras" });
  });
  return list;
}

const NOTIFS_LS_KEY = "pcp.notifs.dismissed.v1";
function loadDismissedNotifs() {
  try {
    const raw = localStorage.getItem(NOTIFS_LS_KEY);
    if (!raw) return [];
    const arr = JSON.parse(raw);
    return Array.isArray(arr) ? arr : [];
  } catch (_) { return []; }
}
function saveDismissedNotifs(ids) {
  try { localStorage.setItem(NOTIFS_LS_KEY, JSON.stringify(ids)); } catch (_) {}
}

function NotificationsBtn({ onGo, app }) {
  const [open, setOpen] = useState(false);
  const [dismissed, setDismissed] = useState(() => loadDismissedNotifs());
  const todos = buildNotifs(app);
  // Limpa do localStorage ids que nao existem mais (condicoes que sumiram)
  const idsAtivos = new Set(todos.map((n) => n.id));
  useEffect(() => {
    const filtrados = dismissed.filter((id) => idsAtivos.has(id));
    if (filtrados.length !== dismissed.length) {
      setDismissed(filtrados); saveDismissedNotifs(filtrados);
    }
  }, [todos.length]);
  const dismissedSet = new Set(dismissed);
  const visiveis = todos.filter((n) => !dismissedSet.has(n.id)).slice(0, 8);

  const dismissOne = (id) => {
    const next = Array.from(new Set([...dismissed, id]));
    setDismissed(next); saveDismissedNotifs(next);
  };
  const dismissAll = () => {
    const next = Array.from(new Set([...dismissed, ...visiveis.map((n) => n.id)]));
    setDismissed(next); saveDismissedNotifs(next);
  };

  return (
    <span className="menu-wrap">
      <span style={{ position: "relative", display: "inline-flex" }}>
        <IconBtn icon="bell" bordered onClick={() => setOpen((o) => !o)} title="Notificações" active={open} />
        {visiveis.length > 0 && (
          <span style={{ position: "absolute", top: 5, right: 5, width: 8, height: 8, borderRadius: "50%", background: "var(--crit)", border: "2px solid var(--bg)" }} />
        )}
      </span>
      {open && (
        <>
          <div className="menu-scrim" onClick={() => setOpen(false)} />
          <div className="menu" style={{ width: 326, padding: 0 }}>
            <div className="row" style={{ justifyContent: "space-between", padding: "11px 13px", borderBottom: "1px solid var(--line)" }}>
              <b style={{ fontSize: 13 }}>Notificações</b>
              {visiveis.length > 0 && <span className="small" style={{ color: "var(--accent)", cursor: "pointer" }} onClick={dismissAll}>Marcar todas lidas</span>}
            </div>
            <div style={{ maxHeight: 320, overflowY: "auto" }}>
              {visiveis.length === 0 ? (
                <div className="small muted" style={{ padding: "16px 14px", textAlign: "center" }}>Nada por aqui — tudo em ordem.</div>
              ) : visiveis.map((nt) => (
                <div key={nt.id} className="row gap12" style={{ padding: "11px 13px", borderBottom: "1px solid var(--line-soft)" }}>
                  <span className="m-ico" style={{ width: 30, height: 30, flex: "none", borderRadius: 8, display: "grid", placeItems: "center", border: "1px solid transparent",
                    color: `var(--${nt.tone})`, background: `var(--${nt.tone}-tint)`, cursor: "pointer" }}
                    onClick={() => { setOpen(false); onGo && onGo(nt.route); }}>
                    <Icon name={nt.ico} size={15} />
                  </span>
                  <div style={{ flex: 1, minWidth: 0, cursor: "pointer" }} onClick={() => { setOpen(false); onGo && onGo(nt.route); }}>
                    <div style={{ fontSize: 12.5, color: "var(--ink)", fontWeight: 500 }}>{nt.t}</div>
                    <div className="small muted">{nt.s}</div>
                  </div>
                  <IconBtn icon="x" title="Dispensar" onClick={(e) => { if (e && e.stopPropagation) e.stopPropagation(); dismissOne(nt.id); }} />
                </div>
              ))}
            </div>
          </div>
        </>
      )}
    </span>
  );
}