/* SkyOps — Commercial · Provider view (drone service company selling inspections). */

const { useState: uSCP, useMemo: uMCP } = React;

function CmProvider({ go, setActiveSite, setActiveMic, setWsStage, period }) {
  const v = useCM();
  const [tab, setTab] = uSCP("overview");
  const [modal, setModal] = uSCP(null);
  const R = cmRange(period);
  const jobs = uMCP(() => cmJobs(v), [v]);
  const billed = jobs.filter(j => j.invoice && cmIn(j.issued, R));
  const rev = billed.reduce((a, j) => a + j.net, 0), cost = billed.reduce((a, j) => a + j.cost, 0);
  const open = jobs.filter(j => j.invoice && j.status !== "paid");
  const ar = open.reduce((a, j) => a + j.net, 0), overdue = open.filter(j => j.status === "overdue");
  const slaSet = jobs.filter(j => (!j.open && cmIn(j.repDate, R)) || j.late), slaPct = slaSet.length ? slaSet.filter(j => j.slaOk).length / slaSet.length * 100 : 100;
  const pipe = v.quotes.filter(q => q.status === "sent").reduce((a, q) => a + cmQuoteTotal(q, v.pb).annual, 0);
  const arr = v.contracts.filter(c => ["active", "signed"].includes(c.status) && c.end >= cmT()).reduce((a, c) => a + c.price * c.cycles, 0);
  const penaltiesDue = jobs.filter(j => j.penPct > 0 && !j.penIssued);
  const invRows = jobs.filter(j => j.invoice && cmIn(j.issued, R));
  const pgQ = usePaged(v.quotes, "cm_quotes"), pgInv = usePaged(invRows, "cm_inv"), pgCn = usePaged(v.cn, "cm_cn"), pgSla = usePaged(jobs, "cm_sla");
  const openJob = (j) => { setActiveSite(j.i.siteId); setActiveMic(j.i.id); setWsStage("report"); go("workspace"); };
  const setQ = (id, patch) => cmStore.set(x => ({ ...x, quotes: x.quotes.map(q => q.id === id ? { ...q, ...patch } : q) }));
  const issuePenalty = (j) => { cmStore.set(x => ({ ...x, cn: [{ id: cmNextId("CN-2026-", x.cn), invoice: j.invoice, micId: j.i.id, amount: j.penAmt, reason: `SLA penalty · report in ${j.wd} wd vs ${j.sla.days} wd (${j.penPct}%)`, date: cmT(), status: "issued", auto: true }, ...x.cn] })); window.skyToast(`Credit note issued · ${cmEur(j.penAmt)} SLA penalty on ${j.invoice}`); };
  const ctStatus = (c) => c.status === "terminated" ? "terminated" : c.start > cmT() ? "signed" : c.end < cmT() ? "expired" : window.skyAdd(60) > c.end ? "expiring" : "active";
  const people = (window.resStore?.data.people || []).filter(p => p.skills.includes("Pilot"));
  const target = { month: 20, quarter: 60, year: 220, all: 220 }[period];
  const util = people.map(p => { const js = jobs.filter(j => j.i.lead === p.name && cmIn(j.i.startedAt, R)); const d = js.reduce((a, j) => a + j.days, 0); return { p, d, n: js.length, wos: (window.woStore?.list || []).filter(w => (w.assignee || "").startsWith(p.name) && !["done", "verified"].includes(w.status)).length, pct: Math.min(100, d / target * 100) }; }).sort((a, b) => b.d - a.d);
  const bySite = Object.values(billed.reduce((m, j) => { const k = j.s.id; m[k] = m[k] || { s: j.s, rev: 0, cost: 0, n: 0 }; m[k].rev += j.net; m[k].cost += j.cost; m[k].n++; return m; }, {})).sort((a, b) => b.rev - a.rev);

  return (<>
    <div className="wo-kpis cm-kpis">
      <div className="wo-kpi"><span className="caps">Invoiced · net</span><b className="mono">{cmEur(rev)}</b><em>{billed.length} invoices · {cmPeriodLabel(period)}</em></div>
      <div className="wo-kpi is-ok"><span className="caps">Gross margin</span><b className="mono">{rev ? ((rev - cost) / rev * 100).toFixed(1) : "0.0"}%</b><em>{cmEur(rev - cost)} on jobs</em></div>
      <div className={`wo-kpi ${overdue.length ? "is-crit" : ""}`}><span className="caps">Receivables</span><b className="mono">{cmEur(ar)}</b><em>{overdue.length} overdue · {cmEur(overdue.reduce((a, j) => a + j.net, 0))}</em></div>
      <div className={`wo-kpi ${slaPct < 90 ? "is-crit" : "is-ok"}`}><span className="caps">SLA met</span><b className="mono">{slaPct.toFixed(0)}%</b><em>{slaSet.filter(j => !j.slaOk).length} breaches · {penaltiesDue.length} penalties to credit</em></div>
      <div className="wo-kpi"><span className="caps">Contracted / yr</span><b className="mono">{cmEur(arr)}</b><em>pipeline {cmEur(pipe)} · {v.quotes.filter(q => q.status === "sent").length} quotes out</em></div>
    </div>
    <div className="cm-tabrow"><div className="tabs">
      {[["overview", "Overview"], ["quotes", `Pipeline · ${v.quotes.length}`], ["contracts", `Contracts · ${v.contracts.length}`], ["invoices", `Invoices · ${jobs.filter(j => j.invoice).length}`], ["sla", "SLA"], ["util", "Utilization"], ["prices", "Price book"]].map(([k, l]) => <button key={k} className={tab === k ? "on" : ""} onClick={() => setTab(k)}>{l}</button>)}
    </div>
    <div className="cm-tabs-act"><button className="btn btn-primary btn-xs" data-perm="commercial.edit" onClick={() => setModal({ t: "quote" })}><Icon name="plus" size={11}/>New quote</button></div></div>

    {tab === "overview" && <div className="cm-2">
      <div className="card"><div className="card-hd">Margin by site<span className="sub">net of credit notes · {cmPeriodLabel(period)}</span></div>
        {bySite.length ? <div className="cm-bars">{bySite.map(r => { const m = (r.rev - r.cost) / r.rev * 100; return (
          <div key={r.s.id} className="cm-bar"><span className="cm-bar-n">{r.s.name}<em>{r.n} jobs · {cmClient(r.s)}</em></span>
            <span className="cm-bar-t"><i className="c" style={{ width: (r.cost / bySite[0].rev * 100) + "%" }}/><i className="m" style={{ width: (Math.max(0, r.rev - r.cost) / bySite[0].rev * 100) + "%" }}/></span>
            <b className="mono">{cmEur(r.rev)}</b><b className={`mono ${m < 25 ? "warn" : "ok"}`}>{m.toFixed(1)}%</b></div>); })}</div> : <div className="tbl-empty">No invoices in this period.</div>}
        <div className="cm-lg"><span><i className="c"/>Cost</span><span><i className="m"/>Margin</span></div>
      </div>
      <div className="card"><div className="card-hd">Needs action</div>
        <div className="cm-act">
          {penaltiesDue.map(j => <div key={"p" + j.i.id} className="cm-act-it warn"><Icon name="alert" size={12}/><span><b>{j.invoice}</b> SLA breach · {j.wd} wd vs {j.sla.days} · penalty {j.penPct}%</span><button className="btn btn-secondary btn-xs" data-perm="commercial.edit" onClick={() => issuePenalty(j)}>Issue credit note {cmEur(j.penAmt)}</button></div>)}
          {overdue.map(j => <div key={j.i.id} className="cm-act-it crit"><Icon name="alert" size={12}/><span><b>{j.invoice}</b> overdue · {j.client} · due {window.skyFmt.date(j.due)}</span><b className="mono">{cmEur(j.net)}</b></div>)}
          {jobs.filter(j => j.late).map(j => <button key={"l" + j.i.id} className="cm-act-it crit" onClick={() => openJob(j)}><Icon name="clock" size={12}/><span><b>{j.i.id}</b> report late by {j.wd - j.sla.days} wd · {j.s.name}{j.ct ? ` · ${j.ct.sla.pct}%/wd penalty` : ""}</span><Icon name="arrow_right" size={11}/></button>)}
          {v.quotes.filter(q => q.status === "sent" && q.valid < window.skyAdd(10)).map(q => <div key={q.id} className="cm-act-it warn"><Icon name="file" size={12}/><span><b>{q.id}</b> expires {window.skyFmt.date(q.valid)} · {q.client}</span></div>)}
          {v.contracts.filter(c => ctStatus(c) === "expiring").map(c => <div key={c.id} className="cm-act-it warn"><Icon name="refresh" size={12}/><span><b>{c.id}</b> ends {window.skyFmt.date(c.end)} · {c.client}</span><button className="btn btn-ghost btn-xs" onClick={() => setModal({ t: "quote", from: c })}>Renewal quote</button></div>)}
          {!penaltiesDue.length && !overdue.length && !jobs.some(j => j.late) && <div className="sec" style={{ fontSize: 12 }}>Nothing pending.</div>}
        </div>
      </div>
    </div>}

    {tab === "quotes" && <div className="card"><table className="tbl">
      <thead><tr><th>Quote</th><th>Client · site</th><th className="r">Area</th><th className="r">Cycles</th><th className="r">Per cycle</th><th className="r">Annual</th><th>Status</th><th>Valid until</th><th className="r"></th></tr></thead>
      <tbody>{v.quotes.length === 0 && <tr><td colSpan={9} className="tbl-empty">No quotes yet.</td></tr>}{pgQ.rows.map(q => { const t = cmQuoteTotal(q, v.pb); const s = cmSite(q.siteId); const exp = q.status === "sent" && q.valid < cmT(); return (
        <tr key={q.id}><td className="mono"><b>{q.id}</b></td><td><b>{q.client}</b><div className="sec cr-sub">{s.name}</div></td><td className="r mono">{window.skyFmt.area(q.area, 1)}</td><td className="r mono">{q.cycles}</td>
          <td className="r mono">{cmEur(t.per)}</td><td className="r mono"><b>{cmEur(t.annual)}</b></td><td><span className={`cm-st cm-st-${exp ? "overdue" : q.status}`}>{exp ? "expired" : q.status}</span>{q.contractId && <div className="sec cr-sub mono">→ {q.contractId}</div>}</td><td className="mono sec">{window.skyFmt.date(q.valid)}</td>
          <td className="r"><div className="cr-acts">
            <button className="btn btn-ghost btn-xs" title="PDF" onClick={() => cmPdf("quote", { id: q.id, to: q.client, site: s.name, date: q.date, valid: q.valid, lines: [[`Thermographic inspection · ${q.area} ha`, q.area * v.pb.perHa], ["Mobilisation", v.pb.mob], ...(q.opts.ortho ? [["RGB orthomosaic", q.area * v.pb.ortho]] : []), ...(q.opts.model3d ? [["3D model", q.area * v.pb.model3d]] : []), ...(q.opts.warranty ? [["Warranty claim pack", v.pb.warranty]] : []), ...(q.rush ? [[`Rush 48 h +${v.pb.rush}%`, null]] : []), [`Per cycle`, t.per], [`${q.cycles} cycles / year`, null]], total: t.annual, note: "SLA: report within 5 working days of flight · coverage >= 95%." })}><Icon name="download" size={11}/></button>
            {q.status === "draft" && <button className="btn btn-secondary btn-xs" data-perm="commercial.edit" onClick={() => { setQ(q.id, { status: "sent", date: cmT(), valid: window.skyAdd(30) }); window.skyToast(`${q.id} sent to ${q.client}`); }}>Send</button>}
            {q.status === "sent" && !exp && <><button className="btn btn-primary btn-xs" data-perm="commercial.edit" onClick={() => setModal({ t: "contract", q })}>Accept → contract</button><button className="btn btn-ghost btn-xs" data-perm="commercial.edit" onClick={() => setQ(q.id, { status: "declined" })}>Declined</button></>}
          </div></td></tr>); })}</tbody></table><Pager pg={pgQ} label="quotes"/></div>}

    {tab === "contracts" && <div className="card"><table className="tbl">
      <thead><tr><th>Contract</th><th>Client · site</th><th>Term</th><th className="r">Cycles used</th><th className="r">Price / cycle</th><th className="r">Annual</th><th>SLA</th><th>Status</th><th className="r"></th></tr></thead>
      <tbody>{v.contracts.map(c => { const st = ctStatus(c); const used = jobs.filter(j => j.i.siteId === c.siteId && j.i.startedAt >= c.start && j.i.startedAt <= c.end).length; return (
        <tr key={c.id}><td className="mono"><b>{c.id}</b>{c.quoteId && <div className="sec cr-sub">from {c.quoteId}</div>}</td><td><b>{c.client}</b><div className="sec cr-sub">{cmSite(c.siteId).name}</div></td>
          <td className="mono sec">{window.skyFmt.date(c.start)} → {window.skyFmt.date(c.end)}</td><td className="r mono">{used}/{c.cycles}</td><td className="r mono">{cmEur(c.price)}</td><td className="r mono"><b>{cmEur(c.price * c.cycles)}</b></td>
          <td className="sec" style={{ fontSize: 11 }}>≤ {c.sla.days} wd · {c.sla.pct}%/wd · cap {c.sla.cap}%</td>
          <td><span className={`cm-st cm-st-${{ active: "accepted", signed: "sent", expiring: "issued", expired: "declined", terminated: "declined" }[st]}`}>{st}</span></td>
          <td className="r"><div className="cr-acts">
            <button className="btn btn-ghost btn-xs" data-perm="commercial.edit" onClick={() => setModal({ t: "sla", c })}>SLA</button>
            {["expiring", "expired"].includes(st) && <button className="btn btn-secondary btn-xs" data-perm="commercial.edit" onClick={() => setModal({ t: "quote", from: c })}>Renew</button>}
            {["active", "signed"].includes(st) && <button className="btn btn-ghost btn-xs" data-perm="commercial.edit" onClick={() => { if (confirm(`Terminate ${c.id}? Future jobs will bill at list price.`)) { cmStore.set(x => ({ ...x, contracts: x.contracts.map(y => y.id === c.id ? { ...y, status: "terminated", end: cmT() } : y) })); window.skyToast(`${c.id} terminated`); } }}>Terminate</button>}
          </div></td></tr>); })}</tbody></table></div>}

    {tab === "invoices" && <><div className="card"><table className="tbl">
      <thead><tr><th>Invoice</th><th>Client · site</th><th>Basis</th><th className="r">Amount</th><th className="r">Credited</th><th className="r">Net</th><th className="r">Margin</th><th>Issued · due</th><th>Status</th><th className="r"></th></tr></thead>
      <tbody>{(() => { const rows = pgInv.rows; return <>{invRows.length === 0 && <tr><td colSpan={10} className="tbl-empty">No invoices in this period.</td></tr>}{rows.map(j => (
        <tr key={j.i.id}><td className="mono"><b>{j.invoice}</b><div className="sec cr-sub"><button className="cm-link" onClick={() => openJob(j)}>{j.i.id}</button></div></td><td><b>{j.client}</b><div className="sec cr-sub">{j.s.name}</div></td>
          <td className="sec" style={{ fontSize: 11 }}>{j.ct ? <>contract <span className="mono">{j.ct.id}</span></> : <span className="cm-warn-t">list price · no contract</span>}</td>
          <td className="r mono">{cmEur(j.amount)}</td><td className="r mono sec">{j.credited ? "−" + cmEur(j.credited) : "—"}</td><td className="r mono"><b>{cmEur(j.net)}</b></td>
          <td className={`r mono ${j.margin / j.net < .25 ? "warn" : ""}`}>{(j.margin / j.net * 100).toFixed(1)}%</td>
          <td className="mono sec" style={{ fontSize: 11 }}>{window.skyFmt.date(j.issued)}<br/>{window.skyFmt.date(j.due)}</td>
          <td><span className={`cm-st cm-st-${j.status === "paid" ? "accepted" : j.status}`}>{j.status}</span>{j.penPct > 0 && !j.penIssued && <div className="cm-warn-t cr-sub">SLA penalty {j.penPct}% pending</div>}</td>
          <td className="r"><div className="cr-acts">
            <button className="btn btn-ghost btn-xs" title="PDF" onClick={() => cmPdf("invoice", { id: j.invoice, to: j.client, site: j.s.name, date: j.issued, due: j.due, lines: [[`${j.i.id} · aerial thermography (IEC TS 62446-3) · ${j.area} ha`, j.amount], [j.ct ? `Per contract ${j.ct.id}` : "List price · no framework contract", null], ...(j.credited ? [["Credit notes applied", -j.credited]] : [])], total: j.net, note: "Payment terms 30 days." })}><Icon name="download" size={11}/></button>
            {j.penPct > 0 && !j.penIssued && <button className="btn btn-secondary btn-xs" data-perm="commercial.edit" onClick={() => issuePenalty(j)}>Apply penalty</button>}
            <button className="btn btn-ghost btn-xs" data-perm="commercial.edit" onClick={() => setModal({ t: "cn", j })}>Credit note</button>
            {j.status !== "paid" && <button className="btn btn-ghost btn-xs" data-perm="commercial.edit" onClick={() => { cmStore.set(x => ({ ...x, inv: { ...x.inv, [j.i.id]: { status: "paid", paidAt: cmT() } } })); window.skyToast(`${j.invoice} marked paid`); }}>Mark paid</button>}
          </div></td></tr>))}</>; })()}</tbody></table>
      <Pager pg={pgInv} label="invoices"/>{jobs.filter(j => !j.invoice).length > 0 && <div className="cm-foot sec">{jobs.filter(j => !j.invoice).length} inspections not yet billable — the invoice is issued when the report is delivered, at the contract price.</div>}
    </div>
    <div className="card" style={{ marginTop: 12 }}><div className="card-hd">Credit notes<span className="sub">{v.cn.length} · {cmEur(v.cn.reduce((a, c) => a + c.amount, 0))}</span></div>
      <table className="tbl"><thead><tr><th>Credit note</th><th>Invoice</th><th>Reason</th><th>Date</th><th className="r">Amount</th><th className="r"></th></tr></thead>
        <tbody>{v.cn.length === 0 && <tr><td colSpan={6} className="tbl-empty">No credit notes. SLA penalties and manual corrections appear here.</td></tr>}{pgCn.rows.map(c => <tr key={c.id}><td className="mono"><b>{c.id}</b>{c.auto && <div className="sec cr-sub">SLA penalty</div>}</td><td className="mono">{c.invoice}</td><td className="sec">{c.reason}</td><td className="mono sec">{window.skyFmt.date(c.date)}</td><td className="r mono">−{cmEur(c.amount)}</td>
          <td className="r"><button className="btn btn-ghost btn-xs" onClick={() => { const j = jobs.find(x => x.invoice === c.invoice); cmPdf("cn", { id: c.id, to: j ? j.client : "—", site: j?.s.name, date: c.date, lines: [[`Against invoice ${c.invoice}`, null], [c.reason, -c.amount]], total: -c.amount }); }}><Icon name="download" size={11}/></button></td></tr>)}</tbody></table><Pager pg={pgCn} label="credit notes"/>
    </div></>}

    {tab === "sla" && <div className="card">
      <div className="card-hd">Report delivery SLA<span className="sub">per contract terms · default ≤ 5 working days from flight</span></div>
      <table className="tbl"><thead><tr><th>Inspection</th><th>Site</th><th>Flight</th><th>Report</th><th className="r">Working days</th><th className="r">Coverage</th><th>Result</th><th className="r">Penalty</th></tr></thead>
        <tbody>{jobs.length === 0 && <tr><td colSpan={8} className="tbl-empty">No inspections in the SLA window.</td></tr>}{pgSla.rows.map(j => (
          <tr key={j.i.id} onClick={() => openJob(j)}><td className="mono"><b>{j.i.id}</b></td><td>{j.s.name}</td><td className="mono sec">{window.skyFmt.date(j.i.startedAt)}</td><td className="mono sec">{j.repDate ? window.skyFmt.date(j.repDate) : "not delivered"}</td>
            <td className="r"><span className="cm-sla"><i style={{ width: Math.min(100, j.wd / 8 * 100) + "%", background: j.wd > j.sla.days ? "var(--sev-critical)" : j.wd > j.sla.days - 2 ? "var(--sev-medium)" : "var(--sev-low)" }}/><em style={{ left: (j.sla.days / 8 * 100) + "%" }}/></span><b className="mono">{j.wd}</b></td>
            <td className={`r mono ${j.i.coverage && j.i.coverage < j.sla.coverage ? "warn" : ""}`}>{j.i.coverage ? j.i.coverage.toFixed(1) + "%" : "—"}</td>
            <td>{j.late ? <span className="cm-st cm-st-overdue">breach · running</span> : j.open ? <span className="cm-st cm-st-sent">on track</span> : j.slaOk ? <span className="cm-st cm-st-accepted">met</span> : <span className="cm-st cm-st-overdue">breach</span>}</td>
            <td className="r mono">{j.penPct ? <span className={j.penIssued ? "sec" : "cm-warn-t"}>{j.penPct}% · {cmEur(j.penAmt)}{j.penIssued ? " ✓" : ""}</span> : "—"}</td></tr>))}</tbody></table><Pager pg={pgSla} label="inspections"/>
    </div>}

    {tab === "util" && <div className="card"><div className="card-hd">Pilot utilization<span className="sub">billable flight days on inspections · target {target} days per {period === "all" ? "year" : period}</span></div>
      <div className="cm-bars">{util.map(({ p, d, n, wos, pct }) => (
        <div key={p.id} className="cm-bar"><span className="cm-bar-n">{p.name}<em>{window.RES_KIND[p.kind]} · {n} inspections{wos ? ` · ${wos} open field WOs (not billable)` : ""}</em></span>
          <span className="cm-bar-t"><i className="m" style={{ width: pct + "%", background: pct > 90 ? "var(--sev-medium)" : undefined }}/></span>
          <b className="mono">{d} d</b><b className={`mono ${pct < 40 ? "warn" : "ok"}`}>{pct.toFixed(0)}%</b></div>))}</div>
    </div>}

    {tab === "prices" && <div className="card st-card">
      <div className="st-card-h">Price book<span>Used by new quotes · contracts lock their own price</span></div>
      {[["perHa", "Thermographic inspection", "€ / ha"], ["mob", "Mobilisation", "€ / cycle"], ["refly", "Re-fly", "€ / sortie"], ["rush", "Rush delivery (48 h)", "% surcharge"], ["ortho", "RGB orthomosaic", "€ / ha"], ["model3d", "3D model / point cloud", "€ / ha"], ["warranty", "Warranty claim pack", "€ / claim"]].map(([k, l, u]) => (
        <div key={k} className="st-row"><div className="st-row-l"><b>{l}</b><span>{u}</span></div><div className="st-row-c"><input className="inp mono st-num" type="number" value={v.pb[k]} disabled={!window.skyCan("commercial.edit")} onChange={e => cmStore.set(x => ({ ...x, pb: { ...x.pb, [k]: +e.target.value } }))}/></div></div>))}
      <div className="st-sub">Cost model</div>
      {[["pilotDay", "Pilot day", "€ / day"], ["droneHour", "Drone operating cost", "€ / flight hour"], ["computeHa", "Processing compute", "€ / ha"], ["reviewHour", "Analyst review", "€ / hour"]].map(([k, l, u]) => (
        <div key={k} className="st-row"><div className="st-row-l"><b>{l}</b><span>{u}</span></div><div className="st-row-c"><input className="inp mono st-num" type="number" value={v.pb[k]} disabled={!window.skyCan("commercial.edit")} onChange={e => cmStore.set(x => ({ ...x, pb: { ...x.pb, [k]: +e.target.value } }))}/></div></div>))}
    </div>}

    {modal?.t === "quote" && <CmQuoteModal pb={v.pb} from={modal.from} onClose={() => setModal(null)}/>}
    {modal?.t === "contract" && <CmContractModal q={modal.q} pb={v.pb} onClose={() => setModal(null)}/>}
    {modal?.t === "sla" && <CmSlaModal c={modal.c} onClose={() => setModal(null)}/>}
    {modal?.t === "cn" && <CmCnModal j={modal.j} onClose={() => setModal(null)}/>}
  </>);
}

function CmQuoteModal({ pb, from, onClose }) {
  const sites = window.ALL_SITES || window.SITES || [];
  const [q, setQ] = uSCP(() => { const s = from ? cmSite(from.siteId) : sites[0]; return { siteId: s.id, client: from ? from.client : cmClient(s), area: window.siteProfile ? +window.siteProfile(s).area.toFixed(1) : 100, cycles: from ? from.cycles : 4, opts: { ortho: false, model3d: false, warranty: false, ...(from?.opts || {}) }, rush: false }; });
  const pickSite = (id) => { const s = sites.find(x => x.id === id); setQ(x => ({ ...x, siteId: id, client: cmClient(s), area: window.siteProfile ? +window.siteProfile(s).area.toFixed(1) : x.area })); };
  const t = cmQuoteTotal(q, pb);
  const save = (status) => { let id; cmStore.set(x => { id = cmNextId("Q-2026-0", x.quotes); return { ...x, quotes: [{ ...q, id, status, date: cmT(), valid: window.skyAdd(30), renews: from?.id }, ...x.quotes] }; }); window.skyToast(status === "sent" ? `${id} sent to ${q.client}` : `${id} saved as draft`); onClose(); };
  return (
    <div className="ni-scrim" onClick={onClose}><div className="ni-modal" onClick={e => e.stopPropagation()} role="dialog">
      <div className="ni-hd"><div><div className="kicker">Commercial{from ? ` · renewal of ${from.id}` : ""}</div><h3>New quote</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
      <div className="ni-body">
        <div className="ni-grid">
          <label className="field"><span>Site</span><select className="sel" value={q.siteId} onChange={e => pickSite(e.target.value)}>{sites.map(s => <option key={s.id} value={s.id}>{s.name}</option>)}</select></label>
          <label className="field"><span>Client</span><input className="inp" value={q.client} onChange={e => setQ(x => ({ ...x, client: e.target.value }))}/></label>
          <label className="field"><span>Area (ha) · from site setup</span><input className="inp mono" type="number" value={q.area} onChange={e => setQ(x => ({ ...x, area: +e.target.value }))}/></label>
          <label className="field"><span>Inspections per year</span><select className="sel" value={q.cycles} onChange={e => setQ(x => ({ ...x, cycles: +e.target.value }))}>{[[12, "Monthly"], [4, "Quarterly"], [2, "Semi-annual"], [1, "Annual"]].map(([n, l]) => <option key={n} value={n}>{l} · {n}</option>)}</select></label>
          <div className="field ni-span"><span>Options</span><div className="fl-skills fl-skills-pick">
            {[["ortho", `RGB orthomosaic · ${cmEur(pb.ortho)}/ha`], ["model3d", `3D model · ${cmEur(pb.model3d)}/ha`], ["warranty", `Warranty claim pack · ${cmEur(pb.warranty)}`]].map(([k, l]) => <button key={k} className={q.opts[k] ? "on" : ""} onClick={() => setQ(x => ({ ...x, opts: { ...x.opts, [k]: !x.opts[k] } }))}>{l}</button>)}
            <button className={q.rush ? "on" : ""} onClick={() => setQ(x => ({ ...x, rush: !x.rush }))}>Rush 48 h · +{pb.rush}%</button></div></div>
        </div>
        <div className="wc-sum">
          <div className="ps-kv"><span>Inspection · {q.area} ha × {cmEur(pb.perHa)}</span><b className="mono">{cmEur(q.area * pb.perHa)}</b></div>
          <div className="ps-kv"><span>Mobilisation</span><b className="mono">{cmEur(pb.mob)}</b></div>
          <div className="ps-kv"><span>Per cycle</span><b className="mono">{cmEur(t.per)}</b></div>
          <div className="ps-kv wc-tot"><span>Annual contract value</span><b className="mono">{cmEur(t.annual)}</b></div>
        </div>
      </div>
      <div className="ni-ft"><span className="grow"/><button className="btn btn-ghost" onClick={onClose}>Cancel</button><button className="btn btn-secondary" onClick={() => save("draft")}>Save draft</button><button className="btn btn-primary" onClick={() => save("sent")}><Icon name="send" size={12}/>Send quote</button></div>
    </div></div>
  );
}

function CmContractModal({ q, pb, onClose }) {
  const t = cmQuoteTotal(q, pb);
  const [f, setF] = uSCP({ start: window.skyAdd(7), months: 12, days: 5, pct: 2, cap: 10 });
  const create = () => {
    let id; cmStore.set(x => { id = cmNextId("CT-2026-0", x.contracts); const end = (() => { const d = new Date(f.start + "T00:00:00Z"); d.setUTCMonth(d.getUTCMonth() + +f.months); d.setUTCDate(d.getUTCDate() - 1); return d.toISOString().slice(0, 10); })();
      return { ...x, quotes: x.quotes.map(y => y.id === q.id ? { ...y, status: "accepted", contractId: id } : y), contracts: [{ id, quoteId: q.id, client: q.client, siteId: q.siteId, start: f.start, end, cycles: q.cycles, price: t.per, opts: q.opts, sla: { days: +f.days, coverage: 95, pct: +f.pct, cap: +f.cap }, status: "signed" }, ...x.contracts] }; });
    window.skyToast(`${q.id} accepted · contract ${id} created at ${cmEur(t.per)} / cycle`); onClose();
  };
  return <div className="ni-scrim" onClick={onClose}><div className="ni-modal" onClick={e => e.stopPropagation()} role="dialog" style={{ width: "min(560px,100%)" }}>
    <div className="ni-hd"><div><div className="kicker">{q.id} · {q.client}</div><h3>Create contract</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
    <div className="ni-body"><div className="ni-grid">
      <label className="field"><span>Start</span><input className="inp" type="date" value={f.start} onChange={e => setF(x => ({ ...x, start: e.target.value }))}/></label>
      <label className="field"><span>Term</span><select className="sel" value={f.months} onChange={e => setF(x => ({ ...x, months: e.target.value }))}><option value={12}>12 months</option><option value={24}>24 months</option><option value={36}>36 months</option></select></label>
      <div className="field ni-span"><span>Locked price</span><div className="inp mono dm-ro">{cmEur(t.per)} / cycle · {q.cycles} cycles / yr<em>from quote · price book changes don't apply</em></div></div>
      <label className="field"><span>SLA · report within (wd)</span><input className="inp mono" type="number" min="1" value={f.days} onChange={e => setF(x => ({ ...x, days: e.target.value }))}/></label>
      <label className="field"><span>Penalty per late wd (%)</span><input className="inp mono" type="number" min="0" value={f.pct} onChange={e => setF(x => ({ ...x, pct: e.target.value }))}/></label>
      <label className="field"><span>Penalty cap (%)</span><input className="inp mono" type="number" min="0" value={f.cap} onChange={e => setF(x => ({ ...x, cap: e.target.value }))}/></label>
    </div></div>
    <div className="ni-ft"><span className="grow"/><button className="btn btn-ghost" onClick={onClose}>Cancel</button><button className="btn btn-primary" onClick={create}><Icon name="check" size={12}/>Accept & create contract</button></div>
  </div></div>;
}

function CmSlaModal({ c, onClose }) {
  const [f, setF] = uSCP({ ...c.sla });
  return <div className="ni-scrim" onClick={onClose}><div className="ni-modal" onClick={e => e.stopPropagation()} role="dialog" style={{ width: "min(480px,100%)" }}>
    <div className="ni-hd"><div><div className="kicker">{c.id} · {c.client}</div><h3>SLA terms</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
    <div className="ni-body"><div className="ni-grid">{[["days", "Report within (wd)"], ["coverage", "Coverage ≥ (%)"], ["pct", "Penalty per late wd (%)"], ["cap", "Penalty cap (%)"]].map(([k, l]) => <label key={k} className="field"><span>{l}</span><input className="inp mono" type="number" value={f[k]} onChange={e => setF(x => ({ ...x, [k]: +e.target.value }))}/></label>)}</div></div>
    <div className="ni-ft"><span className="grow"/><button className="btn btn-ghost" onClick={onClose}>Cancel</button><button className="btn btn-primary" onClick={() => { cmStore.set(x => ({ ...x, contracts: x.contracts.map(y => y.id === c.id ? { ...y, sla: f } : y) })); window.skyToast(`${c.id} SLA updated`); onClose(); }}>Save</button></div>
  </div></div>;
}

function CmCnModal({ j, onClose }) {
  const [f, setF] = uSCP({ amount: "", reason: "Price correction" });
  const ok = +f.amount > 0 && +f.amount <= j.net;
  return <div className="ni-scrim" onClick={onClose}><div className="ni-modal" onClick={e => e.stopPropagation()} role="dialog" style={{ width: "min(480px,100%)" }}>
    <div className="ni-hd"><div><div className="kicker">{j.invoice} · {j.client} · net {cmEur(j.net)}</div><h3>Issue credit note</h3></div><button className="ask-hd-btn" onClick={onClose}><Icon name="x" size={13}/></button></div>
    <div className="ni-body"><div className="ni-grid">
      <label className="field"><span>Amount</span><input className="inp mono" type="number" autoFocus value={f.amount} onChange={e => setF(x => ({ ...x, amount: e.target.value }))}/>{+f.amount > j.net && <em className="dm-err-t">Exceeds net invoice</em>}</label>
      <label className="field"><span>Reason</span><select className="sel" value={f.reason} onChange={e => setF(x => ({ ...x, reason: e.target.value }))}>{["Price correction", "Partial coverage — re-fly not performed", "Goodwill", "Duplicate billing", "Scope reduced"].map(r => <option key={r}>{r}</option>)}</select></label>
    </div></div>
    <div className="ni-ft"><span className="grow"/><button className="btn btn-ghost" onClick={onClose}>Cancel</button><button className="btn btn-primary" disabled={!ok} onClick={() => { cmStore.set(x => ({ ...x, cn: [{ id: cmNextId("CN-2026-", x.cn), invoice: j.invoice, micId: j.i.id, amount: +f.amount, reason: f.reason, date: cmT(), status: "issued" }, ...x.cn] })); window.skyToast(`Credit note issued · ${cmEur(+f.amount)} on ${j.invoice}`); onClose(); }}>Issue</button></div>
  </div></div>;
}

Object.assign(window, { CmProvider });
