/* ============================================================
   PCP — Gastos: despesas gerais da empresa (combustível, materiais,
   equipamentos, taxas...) com nota fiscal anexada.

   Um gasto é o CADASTRO da despesa. Cada ocorrência dele vira um
   lançamento de saída no Financeiro (origem "gasto"), que é o que entra
   no cálculo de lucratividade:
     - única     → 1 lançamento na data informada
     - mensal    → 1 lançamento por mês, da data até o mês corrente
     - parcelado → 1 lançamento por mês, tantos quantos forem as parcelas

   A sincronização é idempotente: roda a cada render das telas Gastos e
   Financeiro e só cria/atualiza/remove o que está fora do lugar.
   (shares global scope; useState etc. from ui.jsx)
   ============================================================ */

const GASTO_TIPOS = [
  "Combustível", "Materiais", "Equipamentos", "Despesa fixa", "Impostos e taxas",
  "Pessoal", "Serviços", "Manutenção", "Marketing", "Frete", "Outros",
];

// Categoria contábil usada pela DRE do Financeiro
const GASTO_CAT = {
  "Materiais": "Matéria-prima",
  "Despesa fixa": "Despesa fixa",
  "Pessoal": "Pessoal",
  "Impostos e taxas": "Impostos",
};
const catDoGasto = (tipo) => GASTO_CAT[tipo] || "Outras";

const GASTO_RECOR = {
  unica: { label: "Única", icon: "dollar" },
  mensal: { label: "Mensal", icon: "refresh" },
  parcelado: { label: "Parcelado", icon: "calendar" },
};

// ---------------- datas (tudo em ISO "YYYY-MM-DD") ----------------
const gHojeISO = () => new Date().toISOString().slice(0, 10);
const gComp = (iso) => String(iso || "").slice(0, 7);            // "2026-08"
const gCompHoje = () => gComp(gHojeISO());
const gMesesEntre = (a, b) => {
  const [ay, am] = a.split("-").map(Number);
  const [by, bm] = b.split("-").map(Number);
  return (by - ay) * 12 + (bm - am);
};
// mesma data, n meses depois (dia limitado ao último dia do mês destino)
const gSomaMeses = (iso, n) => {
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(String(iso || ""));
  if (!m) return iso;
  const y = +m[1], mn = +m[2] - 1, d = +m[3];
  const alvo = new Date(y, mn + n, 1);
  const ultimo = new Date(alvo.getFullYear(), alvo.getMonth() + 1, 0).getDate();
  const dd = Math.min(d, ultimo);
  return `${alvo.getFullYear()}-${String(alvo.getMonth() + 1).padStart(2, "0")}-${String(dd).padStart(2, "0")}`;
};
const gDataBR = (iso) => {
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(String(iso || ""));
  return m ? `${m[3]}/${m[2]}/${m[1].slice(2)}` : (iso || "—");
};
const gMesLabel = (comp) => {
  const m = /^(\d{4})-(\d{2})/.exec(String(comp || ""));
  if (!m) return comp || "";
  const meses = ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"];
  return meses[+m[2] - 1] + "/" + m[1].slice(2);
};
const gFmt = (n) => DB.BRL(+n || 0).replace("R$ ", "R$ ");

// ---------------- ocorrências de um gasto ----------------
// Retorna [{ comp, data, parcela, total }] — uma entrada por mês afetado.
function ocorrenciasGasto(g, hojeIso) {
  if (!g || !g.data) return [];
  const compBase = gComp(g.data);
  let n = 1;
  if (g.recorrencia === "parcelado") n = Math.max(1, Math.min(240, Math.round(+g.parcelas || 1)));
  else if (g.recorrencia === "mensal") n = Math.max(1, Math.min(240, gMesesEntre(compBase, gComp(hojeIso)) + 1));
  const out = [];
  for (let i = 0; i < n; i++) {
    const data = gSomaMeses(g.data, i);
    out.push({ comp: gComp(data), data, parcela: i + 1, total: n });
  }
  return out;
}

// Total que ainda vai vencer de um gasto parcelado
function saldoParcelado(g, hojeIso) {
  if (!g || g.recorrencia !== "parcelado") return 0;
  return ocorrenciasGasto(g, hojeIso).filter((o) => o.data > hojeIso).length * (+g.valor || 0);
}

// ---------------- sincronização com o Financeiro ----------------
// Idempotente: cria o que falta, atualiza o que mudou, remove órfãos.
// Não mexe no `status` de um lançamento já existente (o usuário pode ter
// marcado como pago/pendente na mão).
function sincronizarGastos(app) {
  if (!app || !app.lancamentosApi) return 0;
  const hoje = gHojeISO();
  const esperados = new Map();
  (app.gastos || []).forEach((g) => {
    ocorrenciasGasto(g, hoje).forEach((o) => {
      const sufixo = g.recorrencia === "parcelado" ? ` (${o.parcela}/${o.total})`
        : g.recorrencia === "mensal" ? ` · ${gMesLabel(o.comp)}` : "";
      const key = `gasto:${g._id}:${o.comp}`;
      esperados.set(key, {
        data: o.data,
        desc: (g.desc || "Gasto") + sufixo,
        cat: catDoGasto(g.tipo),
        tipo: "saida",
        valor: +g.valor || 0,
        origem: "gasto",
        origemKey: key,
        gastoId: g._id,
        gastoTipo: g.tipo || "Outros",
        status: o.data > hoje ? "pendente" : "pago",
        venc: o.data,
      });
    });
  });

  let mudou = 0;
  (app.lancamentos || []).filter((l) => l.origem === "gasto").forEach((l) => {
    const alvo = esperados.get(l.origemKey);
    if (!alvo) { app.lancamentosApi.remove(l._id); mudou++; return; }
    esperados.delete(l.origemKey);
    const diff = ["data", "desc", "cat", "valor", "gastoTipo", "venc"].some((k) => l[k] !== alvo[k]);
    if (diff) {
      const semStatus = { ...alvo };
      delete semStatus.status;
      app.lancamentosApi.update(l._id, semStatus);
      mudou++;
    }
  });
  esperados.forEach((v) => { app.lancamentosApi.add(v, true); mudou++; });
  return mudou;
}

// ---------------- formulário ----------------
function NovoGastoForm({ app, onClose, edit }) {
  const [f, setF] = useState(() => ({
    desc: edit ? edit.desc || "" : "",
    tipo: edit ? edit.tipo || "Outros" : "Materiais",
    valor: edit && edit.valor != null ? edit.valor : "",
    data: edit ? edit.data || gHojeISO() : gHojeISO(),
    recorrencia: edit ? edit.recorrencia || "unica" : "unica",
    parcelas: edit && edit.parcelas ? edit.parcelas : 2,
    obs: edit ? edit.obs || "" : "",
  }));
  const [nf, setNf] = useState(edit && edit.nfUrl ? { url: edit.nfUrl, path: edit.nfPath, nome: edit.nfNome } : null);
  const set = (k) => (e) => setF({ ...f, [k]: e.target.value });

  const valorNum = +String(f.valor).replace(",", ".") || 0;
  const parcelasNum = Math.max(1, Math.round(+f.parcelas || 1));
  const previa = f.recorrencia === "parcelado"
    ? `${parcelasNum}× de ${gFmt(valorNum)} = ${gFmt(valorNum * parcelasNum)}`
    : f.recorrencia === "mensal"
      ? `${gFmt(valorNum)} por mês, a partir de ${gDataBR(f.data)}`
      : `${gFmt(valorNum)} em ${gDataBR(f.data)}`;

  const submit = () => {
    const desc = f.desc.trim();
    if (!desc) return app.toast("Informe o que foi o gasto", "crit");
    if (valorNum <= 0) return app.toast("Informe o valor", "crit");
    if (!f.data) return app.toast("Informe a data", "crit");
    const payload = {
      desc, tipo: f.tipo, valor: valorNum, data: f.data,
      recorrencia: f.recorrencia,
      parcelas: f.recorrencia === "parcelado" ? parcelasNum : 0,
      nfUrl: nf ? nf.url : null, nfPath: nf ? nf.path : null, nfNome: nf ? nf.nome : null,
      obs: f.obs.trim(),
    };
    if (edit) app.gastosApi.update(edit._id, payload); else app.gastosApi.add(payload, true);
    app.logEvento && app.logEvento(edit ? "editar_gasto" : "criar_gasto", desc, { valor: valorNum, recorrencia: f.recorrencia });
    onClose();
    app.toast(edit ? "Gasto atualizado" : "Gasto registrado", "ok", { sub: previa, icon: "receipt" });
  };

  return (
    <Modal size="md" icon="receipt" title={edit ? "Editar gasto" : "Novo gasto"}
      sub="Entra como saída no Financeiro" onClose={onClose}
      footer={<><span className="hintnote"><Icon name="wallet" size={14} />{previa}</span><span className="spacer" />
        <Btn onClick={onClose}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={submit}>{edit ? "Salvar alterações" : "Salvar gasto"}</Btn></>}>
      <Field label="O que foi" req><input className="fld" autoFocus value={f.desc} onChange={set("desc")} placeholder="Ex.: Gasolina — entrega dos pedidos" /></Field>
      <div className="field-grid c3" style={{ marginBottom: 14 }}>
        <Field label="Tipo de gasto" req>
          <select className="fld" value={f.tipo} onChange={set("tipo")}>
            {GASTO_TIPOS.map((t) => <option key={t}>{t}</option>)}
          </select>
        </Field>
        <Field label="Valor" req help={f.recorrencia === "unica" ? "" : "valor de cada mês"}>
          <div className="fld-wrap"><span className="pre">R$</span><input className="fld" type="number" step="0.01" min="0" value={f.valor} onChange={set("valor")} placeholder="0,00" /></div>
        </Field>
        <Field label="Data" req>
          <div className="fld-wrap"><Icon name="calendar" size={15} className="ico-in" /><input className="fld" type="date" value={f.data} onChange={set("data")} /></div>
        </Field>
      </div>
      <Field label="Recorrência" help="mensal repete todo mês (ex.: taxa do MEI); parcelado gera uma saída por parcela">
        <Choice value={f.recorrencia} onChange={(v) => setF({ ...f, recorrencia: v })}
          options={[{ v: "unica", l: "Única" }, { v: "mensal", l: "Mensal fixo" }, { v: "parcelado", l: "Parcelado" }]} />
      </Field>
      {f.recorrencia === "parcelado" && (
        <Field label="Parcelas restantes" req help="quantas ainda vão ser pagas, contando a partir da data acima">
          <div className="fld-wrap"><input className="fld right" type="number" min="1" step="1" value={f.parcelas} onChange={set("parcelas")} /><span className="pre">×</span></div>
        </Field>
      )}
      <Field label="Nota fiscal" opt>
        <DocUpload value={nf} onChange={setNf} folder="notas-gastos" toast={app.toast} />
      </Field>
      <Field label="Observações" opt><textarea className="fld" rows={2} value={f.obs} onChange={set("obs")} placeholder="Fornecedor, placa do carro, nº do documento…" /></Field>
    </Modal>
  );
}

// ---------------- tela ----------------
function Gastos({ app }) {
  const [q, setQ] = useState("");
  const [filt, setFilt] = useState("todos");
  const hoje = gHojeISO();
  const compAtual = gCompHoje();

  // mantém o Financeiro em dia com os gastos cadastrados
  useEffect(() => { sincronizarGastos(app); });

  const gastos = app.gastos || [];
  const rows = useMemo(() => {
    const t = q.trim().toLowerCase();
    return gastos.filter((g) => {
      if (filt !== "todos" && (g.recorrencia || "unica") !== filt) return false;
      if (t && !((g.desc || "") + " " + (g.tipo || "") + " " + (g.obs || "")).toLowerCase().includes(t)) return false;
      return true;
    });
  }, [gastos, q, filt]);

  const lancGasto = (app.lancamentos || []).filter((l) => l.origem === "gasto");
  const doMes = lancGasto.filter((l) => gComp(l.data) === compAtual).reduce((s, l) => s + (+l.valor || 0), 0);
  const mensaisFixos = gastos.filter((g) => g.recorrencia === "mensal").reduce((s, g) => s + (+g.valor || 0), 0);
  const aVencer = gastos.reduce((s, g) => s + saldoParcelado(g, hoje), 0);
  const total12 = lancGasto
    .filter((l) => l.data <= hoje && gMesesEntre(gComp(l.data), compAtual) < 12)
    .reduce((s, l) => s + (+l.valor || 0), 0);

  const excluir = (g) => app.openModal("confirm", {
    title: "Excluir gasto?",
    danger: true,
    message: <>O gasto <b>{g.desc}</b> e os lançamentos que ele gerou no Financeiro serão removidos.</>,
    successMsg: "Gasto excluído",
    onConfirm: () => {
      if (g.nfPath && window.pcpStorage) window.pcpStorage.remove(g.nfPath);
      app.gastosApi.remove(g._id);
      (app.lancamentos || []).filter((l) => l.gastoId === g._id).forEach((l) => app.lancamentosApi.remove(l._id));
      app.logEvento && app.logEvento("excluir_gasto", g.desc);
    },
  });

  return (
    <div className="view-inner">
      <div className="page-head head-row">
        <div>
          <div className="crumb">Operação</div>
          <h1 className="page-title">Gastos</h1>
          <p className="page-sub">{gastos.length} cadastrados · {gFmt(doMes)} neste mês · entram como saída no Financeiro</p>
        </div>
        <div className="spacer" />
        <div className="row gap8">
          <Btn icon="wallet" onClick={() => app.setRoute("financeiro")}>Ver no Financeiro</Btn>
          <Btn icon="plus" variant="primary" onClick={() => app.openModal("novoGasto")}>Novo gasto</Btn>
        </div>
      </div>

      <div className="metrics" style={{ gridTemplateColumns: "repeat(4, 1fr)", marginBottom: 18 }}>
        <MetricCard icon="calendar" label="Gastos deste mês" value={gFmt(doMes)} />
        <MetricCard icon="refresh" label="Mensais fixos" value={gFmt(mensaisFixos)} foot="por mês, recorrente" />
        <MetricCard icon="clock" label="Parcelas a vencer" value={gFmt(aVencer)} state={aVencer > 0 ? "warn" : undefined} />
        <MetricCard icon="trendDown" label="Últimos 12 meses" value={gFmt(total12)} />
      </div>

      <div className="card">
        <div className="card-head" style={{ flexWrap: "wrap", rowGap: 8 }}>
          <div className="input" style={{ width: 240, height: 32 }}>
            <Icon name="search" size={15} />
            <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Buscar gasto…" />
          </div>
          <div className="seg">
            {[["todos", "Todos"], ["unica", "Únicos"], ["mensal", "Mensais"], ["parcelado", "Parcelados"]].map(([k, l]) => (
              <button key={k} className={filt === k ? "on" : ""} onClick={() => setFilt(k)}>{l}</button>
            ))}
          </div>
          <span className="spacer" />
          <span className="small muted">{rows.length} de {gastos.length}</span>
        </div>

        <div className="tbl-wrap">
          <table className="tbl">
            <thead>
              <tr>
                <th>Data</th>
                <th>O que foi</th>
                <th>Tipo</th>
                <th>Recorrência</th>
                <th>NF</th>
                <th className="num">Valor</th>
                <th className="num">Total</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {rows.map((g) => {
                const rec = GASTO_RECOR[g.recorrencia || "unica"];
                const ocs = ocorrenciasGasto(g, hoje);
                const restantes = ocs.filter((o) => o.data > hoje).length;
                const total = g.recorrencia === "parcelado" ? (+g.valor || 0) * ocs.length : (+g.valor || 0);
                return (
                  <tr key={g._id}>
                    <td className="mono muted">{gDataBR(g.data)}</td>
                    <td>
                      <span className="strong">{g.desc}</span>
                      {g.obs ? <div className="small muted">{g.obs}</div> : null}
                    </td>
                    <td><Badge>{g.tipo}</Badge></td>
                    <td>
                      <span className="row gap6" style={{ alignItems: "center" }}>
                        <Icon name={rec.icon} size={13} style={{ color: "var(--muted)" }} />
                        <span className="small">{rec.label}</span>
                        {g.recorrencia === "parcelado" && <span className="small muted">· {restantes} a vencer</span>}
                      </span>
                    </td>
                    <td>
                      {g.nfUrl
                        ? <a className="small" href={g.nfUrl} target="_blank" rel="noopener noreferrer" style={{ color: "var(--accent)", fontWeight: 600 }}>Ver nota</a>
                        : <span className="muted small">—</span>}
                    </td>
                    <td className="num strong">{gFmt(g.valor)}</td>
                    <td className="num mono muted">{g.recorrencia === "mensal" ? "mensal" : gFmt(total)}</td>
                    <td>
                      <RowMenu items={[
                        { icon: "edit", label: "Editar", onClick: () => app.openModal("novoGasto", { edit: g }) },
                        ...(g.nfUrl ? [{ icon: "paperclip", label: "Abrir nota fiscal", onClick: () => window.open(g.nfUrl, "_blank", "noopener") }] : []),
                        { icon: "wallet", label: "Ver no Financeiro", onClick: () => app.setRoute("financeiro") },
                        { sep: true },
                        { icon: "trash", label: "Excluir", danger: true, onClick: () => excluir(g) },
                      ]} />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          {rows.length === 0 && (
            <Empty icon="receipt" title={gastos.length ? "Nenhum gasto encontrado" : "Nenhum gasto cadastrado"}
              action={<Btn icon="plus" size="sm" variant="primary" onClick={() => app.openModal("novoGasto")}>Novo gasto</Btn>}>
              Gasolina, materiais, equipamentos, taxa do MEI — tudo que sai do caixa e entra no cálculo do lucro.
            </Empty>
          )}
        </div>
      </div>
    </div>
  );
}

if (window.MODALS) window.MODALS.novoGasto = NovoGastoForm;
Object.assign(window, { Gastos, NovoGastoForm, sincronizarGastos, ocorrenciasGasto, GASTO_TIPOS, catDoGasto, gFmt, gDataBR, gComp });
