/* Sentosa Marketplace - SDC Admin: promotions, loyalty, accounts & campaigns, MICE, reports
   S/No. 79-82, 84, 85  Promotion mechanics - managed centrally by SDC (Reply No. 4 Q13)
   S/No. 86, 87, 88     Automated commission calculation, multi-format rebate, tier-based structure
   S/No. 154a           Native accounts and campaign management where Salesforce CRM is not activated
   S/No. 143, 144a      MICE venue and offer management, and native enquiry management
   S/No. 95-108         Reports register */

/* ---------------- Promotions ---------------- */
function AdminPromotionsScreen({ approved, onApprove }) {
  const [mech, setMech] = React.useState("All");
  const [creating, setCreating] = React.useState(false);
  const [created, setCreated] = React.useState(null);
  const mechs = ["All", "Percentage", "Fixed amount", "Bundle", "Card-based", "Coupon", "Complimentary"];
  const all = (created ? [created] : []).concat(window.ADMIN_PROMOS);
  const rows = all.filter(p => mech === "All" || p.mech === mech);
  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 12, padding: 16, background: "var(--info-bg)",
        border: "1px solid #c4d4f7", borderRadius: "var(--radius-md)" }}>
        <Icon name="info" size={19} color="#1a44a8" style={{ marginTop: 1 }} />
        <div style={{ fontSize: 13.5, color: "#1a44a8", lineHeight: 1.55 }}>
          Promotions are managed centrally here. Island partners may raise requests through the seller portal, but every promotion
          must be configured and approved by an SDC admin before it goes live.
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 18 }}>
        <AKpi label="Live promotions" value="3" icon="tag" />
        <AKpi label="Pending approval" value="1" icon="clock" />
        <AKpi label="Redemptions (MTD)" value="12,960" delta="+18.4%" up icon="ticket" />
        <AKpi label="Attributed uplift" value="+8.4%" delta="+1.2pp" up icon="trending-up" />
      </div>

      <Card pad={0}>
        <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" }}>
          <div style={{ fontWeight: 600 }}>All promotions</div>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginLeft: 12 }}>
            {mechs.map(m => (
              <button key={m} onClick={() => setMech(m)}
                style={{ padding: "6px 12px", borderRadius: "var(--radius-pill)", cursor: "pointer", fontFamily: "var(--font-sans)",
                  fontSize: 12.5, fontWeight: mech === m ? 600 : 500,
                  border: "1px solid " + (mech === m ? "var(--black)" : "var(--border)"),
                  background: mech === m ? "var(--black)" : "#fff", color: mech === m ? "#fff" : "var(--fg2)" }}>{m}</button>
            ))}
          </div>
          <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
            <ExportButtons name="Promotion report" rows={rows.length} />
            <Btn size="sm" variant="primary" icon="plus" onClick={() => setCreating(true)}>Create promotion</Btn>
          </div>
        </div>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 1020 }}>
            <thead><tr>
              <th style={ATH}>Reference</th><th style={ATH}>Name</th><th style={ATH}>Mechanic</th><th style={ATH}>Value</th>
              <th style={ATH}>Applies to</th><th style={ATH}>Partner</th><th style={ATH}>Period</th>
              <th style={{ ...ATH, textAlign: "right" }}>Redeemed</th><th style={ATH}>Status</th><th style={ATH}></th>
            </tr></thead>
            <tbody>
              {rows.map(p => {
                const st = approved[p.ref] || p.status;
                return (
                  <tr key={p.ref}>
                    <td style={{ ...ATD, fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 13.5 }}>{p.ref}</td>
                    <td style={{ ...ATD, fontWeight: 600 }}>{p.name}</td>
                    <td style={ATD}>{p.mech}</td>
                    <td style={{ ...ATD, fontWeight: 600 }}>{p.value}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{p.scope}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{p.partner}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{p.period}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>{p.redeemed.toLocaleString()}</td>
                    <td style={ATD}><Badge tone={tone(st)}>{st}</Badge></td>
                    <td style={{ ...ATD, textAlign: "right" }}>
                      {st === "Pending approval"
                        ? <Btn size="sm" variant="primary" icon="check" onClick={() => onApprove(p.ref)}>Approve</Btn>
                        : <span style={{ color: "var(--fg3)", fontSize: 13 }}>-</span>}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>

      <CreatePromotionModal open={creating} onClose={() => setCreating(false)}
        onCreate={(p) => { setCreated(p); setCreating(false); window.toast("Promotion created and published", "success", `${p.name} · live ${p.period}`); }} />
    </div>
  );
}

/* Create a marketplace promotion - S/No. 79-82, 84, 85 */
function CreatePromotionModal({ open, onClose, onCreate }) {
  const blank = { name: "", mech: "Percentage", value: "", scope: "All products", partner: "SDC", period: "" };
  const [f, setF] = React.useState(blank);
  React.useEffect(() => { if (open) setF(blank); }, [open]);
  const set = (k) => (e) => setF(p => ({ ...p, [k]: e.target.value }));
  const ok = f.name.trim() && f.value.trim() && f.period.trim();
  return (
    <Modal open={open} onClose={onClose} width={620}
      title="Create promotion"
      subtitle="Configured centrally by SDC. Goes live immediately on creation."
      footer={<>
        <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
        <Btn variant="primary" icon="check" disabled={!ok}
          onClick={() => ok && onCreate({ ref: "PRM-2047", ...f, status: "Live", redeemed: 0, uplift: 0 })}>
          Create and publish
        </Btn>
      </>}>
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        <Field label="Promotion name" required value={f.name} onChange={set("name")} placeholder="e.g. National Day trade offer" />
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <Field label="Mechanic" as="select" value={f.mech} onChange={set("mech")}>
            <option>Percentage</option><option>Fixed amount</option><option>Complimentary</option>
            <option>Bundle</option><option>Card-based</option><option>Coupon</option>
          </Field>
          <Field label="Value" required value={f.value} onChange={set("value")} placeholder="e.g. 12% or S$5" />
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <Field label="Applies to" as="select" value={f.scope} onChange={set("scope")}>
            <option>All products</option><option>Island Admission - Day Pass</option>
            <option>Cable Car Sky Pass</option><option>Multi-Attraction Pass (3-in-1)</option>
            <option>MICE Welcome Reception Pass</option>
          </Field>
          <Field label="Island partner" as="select" value={f.partner} onChange={set("partner")}>
            <option>SDC</option><option>Sentosa Cable Car</option><option>Skyline Luge</option>
            <option>Marine Life Park</option><option>Tanjong Beach Club</option><option>Sentosa MICE</option>
          </Field>
        </div>
        <Field label="Period" required value={f.period} onChange={set("period")} placeholder="e.g. 1-31 Aug 2026" />
      </div>
    </Modal>
  );
}

/* ---------------- Loyalty: commission & rebate ---------------- */
function LoyaltyScreen() {
  const [tab, setTab] = React.useState("commission");
  const [editing, setEditing] = React.useState(null);
  const totalYtd = window.COMMISSION_RULES.reduce((s, r) => s + r.ytd, 0);
  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 18 }}>
        <AKpi label="Commission earned (YTD)" value={`S$${(totalYtd / 1000).toFixed(0)}k`} delta="+16.8%" up icon="percent" />
        <AKpi label="Rebates accrued (YTD)" value="S$184k" delta="+9.1%" up icon="badge-dollar-sign" />
        <AKpi label="Accounts on a rebate tier" value="274" sub="of 488 active" icon="award" />
        <AKpi label="Average commission rate" value="11.5%" icon="calculator" />
      </div>

      <div style={{ display: "flex", gap: 6, borderBottom: "1px solid var(--border)" }}>
        {[["commission", "Commission rules"], ["rebate", "Rebate tiers"]].map(([k, label]) => (
          <button key={k} onClick={() => setTab(k)}
            style={{ background: "none", border: 0, cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 14.5,
              fontWeight: tab === k ? 600 : 500, color: tab === k ? "var(--fg1)" : "var(--fg2)", padding: "10px 14px",
              borderBottom: tab === k ? "2px solid var(--action)" : "2px solid transparent", marginBottom: -1 }}>{label}</button>
        ))}
      </div>

      {tab === "commission" ? (
        <Card pad={0}>
          <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
            <div>
              <div style={{ fontWeight: 600 }}>Commission by island partner</div>
              <div className="caption">Calculated automatically on the selling rate, after operating costs and bank charges.</div>
            </div>
            <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
              <ExportButtons name="Commission tracking report" rows={window.COMMISSION_RULES.length} />
              <Btn size="sm" variant="secondary" icon="plus" onClick={() => setEditing({ partner: "", category: "Attraction", rate: 12, basis: "Selling rate", isNew: true })}>Add rule</Btn>
            </div>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 760 }}>
              <thead><tr>
                <th style={ATH}>Island partner</th><th style={ATH}>Category</th><th style={ATH}>Basis</th>
                <th style={{ ...ATH, textAlign: "right" }}>Rate</th><th style={{ ...ATH, textAlign: "right" }}>Commission YTD</th><th style={ATH}></th>
              </tr></thead>
              <tbody>
                {window.COMMISSION_RULES.map(r => (
                  <tr key={r.partner}>
                    <td style={{ ...ATD, fontWeight: 600 }}>{r.partner}</td>
                    <td style={ATD}>{r.category}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{r.basis}</td>
                    <td style={{ ...ATD, textAlign: "right", fontWeight: 600 }}>{r.rate.toFixed(1)}%</td>
                    <td style={{ ...ATD, textAlign: "right", fontFamily: "var(--font-mono)", fontSize: 13.5 }}>S${r.ytd.toLocaleString()}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>
                      <button onClick={() => setEditing(r)} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--orange-link)",
                        fontWeight: 600, fontFamily: "var(--font-sans)", fontSize: 14, display: "inline-flex", alignItems: "center", gap: 5 }}>
                        <Icon name="pencil" size={15} />Edit</button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <CommissionRuleModal rule={editing} onClose={() => setEditing(null)} />
        </Card>
      ) : (
        <>
          <Card pad={20}>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 4 }}>Tier-based rebate structure</div>
            <p className="caption" style={{ marginBottom: 18 }}>
              Rebates accrue automatically against annual trade volume. Buyers move tier as their YTD volume crosses each threshold.
            </p>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 16 }}>
              {window.REBATE_TIERS.map(t => (
                <div key={t.tier} style={{ border: "1px solid var(--border)", borderRadius: "var(--radius-lg)", overflow: "hidden" }}>
                  <div style={{ height: 5, background: t.colour }}></div>
                  <div style={{ padding: 16 }}>
                    <div style={{ fontSize: 16, fontWeight: 700 }}>{t.tier}</div>
                    <div style={{ fontSize: 12.5, color: "var(--fg2)", marginTop: 3 }}>
                      {t.threshold === 0 ? "Entry tier" : `From S$${t.threshold.toLocaleString()} / year`}
                    </div>
                    <div style={{ fontSize: 26, fontWeight: 700, marginTop: 12 }}>{t.rebate.toFixed(1)}<span style={{ fontSize: 16 }}>%</span></div>
                    <div style={{ fontSize: 12.5, color: "var(--fg2)" }}>rebate on trade volume</div>
                    <div style={{ marginTop: 12, paddingTop: 12, borderTop: "1px solid var(--border)", fontSize: 13 }}>
                      <strong>{t.accounts}</strong> <span style={{ color: "var(--fg2)" }}>accounts</span>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </Card>
          <Card pad={20}>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 14 }}>Rebate formats supported</div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 14 }}>
              {[["percent", "Percentage of volume", "Applied to net trade volume over the rebate period."],
                ["banknote", "Fixed amount per unit", "A set rebate per ticket or per booking, by product category."],
                ["wallet", "eWallet credit", "Rebate credited directly to the buyer's platform eWallet."]].map(([ic, h, b]) => (
                <div key={h} style={{ display: "flex", gap: 11, padding: 14, border: "1px solid var(--border)", borderRadius: "var(--radius-md)" }}>
                  <Icon name={ic} size={19} color="var(--orange-700)" style={{ marginTop: 1, flex: "none" }} />
                  <div><div style={{ fontSize: 14, fontWeight: 600 }}>{h}</div>
                    <div style={{ fontSize: 13, color: "var(--fg2)", lineHeight: 1.5, marginTop: 3 }}>{b}</div></div>
                </div>
              ))}
            </div>
          </Card>
        </>
      )}
    </div>
  );
}

/* ---------------- Accounts & campaigns (S/No. 154a) ---------------- */
function AccountsScreen() {
  const [tab, setTab] = React.useState("accounts");
  const [newAcct, setNewAcct] = React.useState(false);
  const [newCamp, setNewCamp] = React.useState(false);
  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 12, padding: 16, background: "var(--neutral-50)",
        border: "1px solid var(--border)", borderRadius: "var(--radius-md)" }}>
        <Icon name="shield-check" size={19} color="var(--fg2)" style={{ marginTop: 1 }} />
        <div style={{ fontSize: 13.5, color: "var(--fg2)", lineHeight: 1.55 }}>
          Account and campaign management runs natively in the marketplace. Salesforce CRM integration is optional - where SDC
          elects not to activate it, these functions remain fully operational here.
        </div>
      </div>

      <div style={{ display: "flex", gap: 6, borderBottom: "1px solid var(--border)" }}>
        {[["accounts", "Trade accounts"], ["campaigns", "Campaigns"]].map(([k, label]) => (
          <button key={k} onClick={() => setTab(k)}
            style={{ background: "none", border: 0, cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 14.5,
              fontWeight: tab === k ? 600 : 500, color: tab === k ? "var(--fg1)" : "var(--fg2)", padding: "10px 14px",
              borderBottom: tab === k ? "2px solid var(--action)" : "2px solid transparent", marginBottom: -1 }}>{label}</button>
        ))}
      </div>

      {tab === "accounts" ? (
        <Card pad={0}>
          <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
            <div style={{ fontWeight: 600 }}>Trade accounts</div>
            <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
              <ExportButtons name="Account management report" rows={window.ACCOUNTS.length} />
              <Btn size="sm" variant="primary" icon="plus" onClick={() => setNewAcct(true)}>New account</Btn>
            </div>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 960 }}>
              <thead><tr>
                <th style={ATH}>Account</th><th style={ATH}>Type</th><th style={ATH}>Tier</th>
                <th style={{ ...ATH, textAlign: "right" }}>Sub-users</th><th style={{ ...ATH, textAlign: "right" }}>Volume YTD</th>
                <th style={ATH}>Owner</th><th style={ATH}>Last order</th><th style={ATH}>Status</th>
              </tr></thead>
              <tbody>
                {window.ACCOUNTS.map(a => (
                  <tr key={a.name}>
                    <td style={{ ...ATD, fontWeight: 600 }}>{a.name}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{a.type}</td>
                    <td style={ATD}><Badge tone={a.tier === "Platinum" ? "info" : a.tier === "Gold" ? "warning" : "neutral"} dot={false}>{a.tier}</Badge></td>
                    <td style={{ ...ATD, textAlign: "right" }}>{a.subusers}</td>
                    <td style={{ ...ATD, textAlign: "right", fontFamily: "var(--font-mono)", fontSize: 13.5 }}>S${a.ytd.toLocaleString()}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{a.owner}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{a.lastOrder}</td>
                    <td style={ATD}><Badge tone={tone(a.status)}>{a.status}</Badge></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </Card>
      ) : (
        <Card pad={0}>
          <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
            <div>
              <div style={{ fontWeight: 600 }}>Campaigns</div>
              <div className="caption">Performance tracked natively - sends, opens, conversions and attributed revenue.</div>
            </div>
            <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
              <ExportButtons name="Campaign performance report" rows={window.CAMPAIGNS.length} />
              <Btn size="sm" variant="primary" icon="plus" onClick={() => setNewCamp(true)}>New campaign</Btn>
            </div>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 1000 }}>
              <thead><tr>
                <th style={ATH}>Reference</th><th style={ATH}>Campaign</th><th style={ATH}>Segment</th><th style={ATH}>Channel</th>
                <th style={{ ...ATH, textAlign: "right" }}>Sent</th><th style={{ ...ATH, textAlign: "right" }}>Opened</th>
                <th style={{ ...ATH, textAlign: "right" }}>Converted</th><th style={{ ...ATH, textAlign: "right" }}>Revenue</th><th style={ATH}>Status</th>
              </tr></thead>
              <tbody>
                {window.CAMPAIGNS.map(c => (
                  <tr key={c.ref}>
                    <td style={{ ...ATD, fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 13.5 }}>{c.ref}</td>
                    <td style={{ ...ATD, fontWeight: 600 }}>{c.name}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{c.segment}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{c.channel}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>{c.sent}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>{c.opened}</td>
                    <td style={{ ...ATD, textAlign: "right", fontWeight: 600 }}>{c.converted}</td>
                    <td style={{ ...ATD, textAlign: "right", fontFamily: "var(--font-mono)", fontSize: 13.5 }}>S${c.revenue.toLocaleString()}</td>
                    <td style={ATD}><Badge tone={tone(c.status)}>{c.status}</Badge></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </Card>
      )}

      <SimpleFormModal open={newAcct} onClose={() => setNewAcct(false)} width={600}
        title="New trade account" subtitle="Creates the account and issues portal credentials. Sub-users are added by the account owner."
        submitLabel="Create account"
        fields={[
          { k: "name", label: "Organisation name", required: true, placeholder: "e.g. Horizon Travel Pte Ltd" },
          { k: "uen", label: "UEN", required: true, placeholder: "e.g. 202112345A" },
          { k: "type", label: "Account type", as: "select", options: ["Travel agent", "OTA", "MICE organiser", "Corporate"] },
          { k: "tier", label: "Starting tier", as: "select", options: ["Bronze", "Silver", "Gold", "Platinum"] },
          { k: "email", label: "Primary contact email", required: true, type: "email", placeholder: "bookings@example.com" },
          { k: "owner", label: "Account owner", as: "select", options: ["A. Lim", "J. Chua"] },
        ]}
        onSubmit={(v) => window.toast("Trade account created", "success", `${v.name} · credentials issued to ${v.email}`)} />

      <SimpleFormModal open={newCamp} onClose={() => setNewCamp(false)} width={600}
        title="New campaign" subtitle="Native campaign management. Performance is tracked against attributed revenue."
        submitLabel="Launch campaign"
        fields={[
          { k: "name", label: "Campaign name", required: true, placeholder: "e.g. Q4 MICE activation" },
          { k: "segment", label: "Segment", as: "select", options: ["All trade accounts", "Silver & Bronze agents", "MICE organisers", "No order in 90 days", "Platinum & Gold"] },
          { k: "channel", label: "Channel", as: "select", options: ["Email", "In-platform", "Email + in-platform"] },
          { k: "period", label: "Period", required: true, placeholder: "e.g. Oct - Dec 2026" },
          { k: "goal", label: "Objective", as: "textarea", placeholder: "What this campaign is meant to shift…" },
        ]}
        onSubmit={(v) => window.toast("Campaign launched", "success", `${v.name} · ${v.segment}`)} />
    </div>
  );
}

/* Generic create/edit form modal */
function SimpleFormModal({ open, onClose, title, subtitle, fields, onSubmit, submitLabel = "Save", width = 580 }) {
  const blank = () => Object.fromEntries(fields.map(f => [f.k, f.options ? f.options[0] : ""]));
  const [v, setV] = React.useState(blank);
  React.useEffect(() => { if (open) setV(blank()); }, [open]);
  const set = (k) => (e) => setV(p => ({ ...p, [k]: e.target.value }));
  const ok = fields.filter(f => f.required).every(f => String(v[f.k] || "").trim());
  return (
    <Modal open={open} onClose={onClose} title={title} subtitle={subtitle} width={width}
      footer={<>
        <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
        <Btn variant="primary" icon="check" disabled={!ok} onClick={() => { onSubmit(v); onClose(); }}>{submitLabel}</Btn>
      </>}>
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        {fields.map(f => f.as === "select"
          ? <Field key={f.k} label={f.label} as="select" value={v[f.k]} onChange={set(f.k)}>
              {f.options.map(o => <option key={o}>{o}</option>)}
            </Field>
          : <Field key={f.k} label={f.label} as={f.as} type={f.type} required={f.required}
              value={v[f.k]} onChange={set(f.k)} placeholder={f.placeholder} />)}
      </div>
    </Modal>
  );
}

/* Commission rule editor */
function CommissionRuleModal({ rule, onClose }) {
  const [v, setV] = React.useState({ partner: "", category: "Attraction", rate: "", basis: "Selling rate" });
  React.useEffect(() => {
    if (rule) setV({ partner: rule.partner || "", category: rule.category || "Attraction",
      rate: rule.rate != null ? String(rule.rate) : "", basis: rule.basis || "Selling rate" });
  }, [rule]);
  const set = (k) => (e) => setV(p => ({ ...p, [k]: e.target.value }));
  const ok = v.partner.trim() && String(v.rate).trim();
  return (
    <Modal open={!!rule} onClose={onClose} width={560}
      title={rule && rule.isNew ? "Add commission rule" : "Edit commission rule"}
      subtitle="Commission is calculated automatically on the selling rate, after operating costs and bank charges."
      footer={<>
        <Btn variant="ghost" onClick={onClose}>Cancel</Btn>
        <Btn variant="primary" icon="check" disabled={!ok}
          onClick={() => { window.toast("Commission rule saved", "success", `${v.partner} · ${v.rate}% on ${v.basis.toLowerCase()}`); onClose(); }}>
          Save rule
        </Btn>
      </>}>
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        <Field label="Island partner" required value={v.partner} onChange={set("partner")} placeholder="e.g. Sentosa Cable Car" />
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <Field label="Category" as="select" value={v.category} onChange={set("category")}>
            <option>Attraction</option><option>Experience</option><option>Dining</option>
            <option>MICE</option><option>Island admission</option>
          </Field>
          <Field label="Commission rate (%)" required value={v.rate} onChange={set("rate")} placeholder="12.0" />
        </div>
        <Field label="Basis" as="select" value={v.basis} onChange={set("basis")}>
          <option>Selling rate</option><option>Net settlement rate</option><option>Fixed per unit</option>
        </Field>
      </div>
    </Modal>
  );
}

/* ---------------- MICE (S/No. 143, 144a) ---------------- */
function AdminMiceScreen({ assigned, onAssign }) {
  const [tab, setTab] = React.useState("enquiries");
  const [addVenue, setAddVenue] = React.useState(false);
  const [editVenue, setEditVenue] = React.useState(null);
  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 18 }}>
        <AKpi label="Open enquiries" value="3" icon="inbox" />
        <AKpi label="Unassigned" value={assigned["ENQ-10462"] ? "0" : "1"} icon="user-x" />
        <AKpi label="Published venues" value="5" sub="1 in draft" icon="map-pin" />
        <AKpi label="Pipeline value" value="S$412k" delta="+22.1%" up icon="trending-up" />
      </div>

      <div style={{ display: "flex", gap: 6, borderBottom: "1px solid var(--border)" }}>
        {[["enquiries", "Enquiry queue"], ["venues", "Venue & offer management"]].map(([k, label]) => (
          <button key={k} onClick={() => setTab(k)}
            style={{ background: "none", border: 0, cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 14.5,
              fontWeight: tab === k ? 600 : 500, color: tab === k ? "var(--fg1)" : "var(--fg2)", padding: "10px 14px",
              borderBottom: tab === k ? "2px solid var(--action)" : "2px solid transparent", marginBottom: -1 }}>{label}</button>
        ))}
      </div>

      {tab === "enquiries" ? (
        <>
          <div style={{ display: "flex", alignItems: "flex-start", gap: 12, padding: 16, background: "var(--neutral-50)",
            border: "1px solid var(--border)", borderRadius: "var(--radius-md)" }}>
            <Icon name="shield-check" size={19} color="var(--fg2)" style={{ marginTop: 1 }} />
            <div style={{ fontSize: 13.5, color: "var(--fg2)", lineHeight: 1.55 }}>
              Enquiries submitted through the buyer portal are retained and managed here. Where SDC activates the optional
              Salesforce integration, the same enquiry is also pushed as a lead - this queue continues to work either way.
            </div>
          </div>
          <Card pad={0}>
            <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", fontWeight: 600 }}>Enquiry queue</div>
            <div style={{ overflowX: "auto" }}>
              <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 1040 }}>
                <thead><tr>
                  <th style={ATH}>Reference</th><th style={ATH}>Organisation</th><th style={ATH}>Event</th><th style={ATH}>Venue</th>
                  <th style={{ ...ATH, textAlign: "right" }}>Pax</th><th style={ATH}>Dates</th><th style={ATH}>Owner</th>
                  <th style={ATH}>Status</th><th style={ATH}></th>
                </tr></thead>
                <tbody>
                  {window.ADMIN_ENQUIRIES.map(e => {
                    const owner = assigned[e.ref] || e.owner;
                    return (
                      <tr key={e.ref}>
                        <td style={{ ...ATD, fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 13.5 }}>{e.ref}</td>
                        <td style={{ ...ATD, fontWeight: 600 }}>{e.org}</td>
                        <td style={ATD}>{e.event}</td>
                        <td style={{ ...ATD, color: "var(--fg2)" }}>{e.venue}</td>
                        <td style={{ ...ATD, textAlign: "right" }}>{e.pax}</td>
                        <td style={{ ...ATD, color: "var(--fg2)" }}>{e.date}</td>
                        <td style={ATD}>{owner === "Unassigned"
                          ? <span style={{ color: "var(--danger)", fontWeight: 600, fontSize: 13.5 }}>Unassigned</span>
                          : owner}</td>
                        <td style={ATD}><Badge tone={tone(e.status)}>{e.status}</Badge></td>
                        <td style={{ ...ATD, textAlign: "right" }}>
                          {owner === "Unassigned"
                            ? <Btn size="sm" variant="primary" icon="user-check" onClick={() => onAssign(e.ref)}>Assign to me</Btn>
                            : <span style={{ color: "var(--fg3)", fontSize: 13 }}>-</span>}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </Card>
        </>
      ) : (
        <Card pad={0}>
          <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
            <div>
              <div style={{ fontWeight: 600 }}>Venues &amp; offers</div>
              <div className="caption">Listings, capacity, indicative pricing and publication status, managed by the SDC MICE team.</div>
            </div>
            <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
              <ExportButtons name="MICE venue report" rows={window.ADMIN_VENUES.length} />
              <Btn size="sm" variant="primary" icon="plus" onClick={() => setAddVenue(true)}>Add venue</Btn>
            </div>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 820 }}>
              <thead><tr>
                <th style={ATH}>Venue</th><th style={ATH}>Operator</th>
                <th style={{ ...ATH, textAlign: "right" }}>Capacity</th><th style={{ ...ATH, textAlign: "right" }}>Indicative rate</th>
                <th style={{ ...ATH, textAlign: "right" }}>Enquiries</th><th style={ATH}>Status</th><th style={ATH}></th>
              </tr></thead>
              <tbody>
                {window.ADMIN_VENUES.map(v => (
                  <tr key={v.name}>
                    <td style={{ ...ATD, fontWeight: 600 }}>{v.name}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{v.partner}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>{v.cap.toLocaleString()}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>S${v.rate.toLocaleString()}</td>
                    <td style={{ ...ATD, textAlign: "right" }}>{v.enquiries}</td>
                    <td style={ATD}><Badge tone={tone(v.status)}>{v.status}</Badge></td>
                    <td style={{ ...ATD, textAlign: "right" }}>
                      <button onClick={() => setEditing(r)} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--orange-link)",
                        fontWeight: 600, fontFamily: "var(--font-sans)", fontSize: 14, display: "inline-flex", alignItems: "center", gap: 5 }}>
                        <Icon name="pencil" size={15} />Edit</button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <CommissionRuleModal rule={editing} onClose={() => setEditing(null)} />
        </Card>
      )}

      <SimpleFormModal open={addVenue} onClose={() => setAddVenue(false)} width={620}
        title="Add MICE venue" subtitle="Published venues appear in buyer-side AI venue discovery."
        submitLabel="Save as draft"
        fields={[
          { k: "name", label: "Venue name", required: true, placeholder: "e.g. Palawan Pavilion" },
          { k: "partner", label: "Operator", required: true, placeholder: "e.g. Sentosa MICE" },
          { k: "cap", label: "Maximum capacity (pax)", required: true, placeholder: "e.g. 600" },
          { k: "rate", label: "Indicative rate (S$/day)", required: true, placeholder: "e.g. 8800" },
          { k: "layout", label: "Primary layout", as: "select", options: ["Divisible ballroom", "Open lawn", "Outdoor amphitheatre", "Waterfront cocktail", "Banquet / theatre", "Beach club buyout"] },
          { k: "lead", label: "Lead time", as: "select", options: ["14 days", "21 days", "30 days", "60 days"] },
        ]}
        onSubmit={(v) => window.toast("Venue created", "success", `${v.name} · saved as draft, not yet published`)} />

      <SimpleFormModal open={!!editVenue} onClose={() => setEditVenue(null)} width={620}
        title={editVenue ? `Edit ${editVenue.name}` : "Edit venue"}
        subtitle="Changes to a published venue appear immediately in buyer-side discovery."
        submitLabel="Save changes"
        fields={[
          { k: "cap", label: "Maximum capacity (pax)", required: true, placeholder: editVenue ? String(editVenue.cap) : "" },
          { k: "rate", label: "Indicative rate (S$/day)", required: true, placeholder: editVenue ? String(editVenue.rate) : "" },
          { k: "status", label: "Publication status", as: "select", options: ["Published", "Draft", "Unpublished"] },
          { k: "note", label: "Internal note", as: "textarea", placeholder: "Visible to the SDC MICE team only…" },
        ]}
        onSubmit={() => window.toast("Venue updated", "success", editVenue ? `${editVenue.name} · synchronised to discovery` : "")} />
    </div>
  );
}

/* ---------------- Reports ---------------- */
function AdminReportsScreen() {
  const groups = [...new Set(window.ADMIN_REPORTS.map(r => r.group))];
  const [report, setReport] = React.useState(null);
  const data = report ? (ADMIN_REPORT_DATA[report.name] || ADMIN_REPORT_DATA._default) : null;
  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <Card pad={18}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 15.5 }}>Reporting</div>
            <div className="caption">Role-configurable views for buyers, sellers and SDC admin. Scheduled distribution to configured mailboxes.</div>
          </div>
          <div style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
            <Btn size="sm" variant="secondary" icon="calendar"
              onClick={() => window.toast("Report schedule saved", "info", "Weekly, Mondays 08:00 · sent to configured mailboxes")}>Schedule</Btn>
            <ExportButtons name="Full report pack" rows={window.ADMIN_REPORTS.length} />
          </div>
        </div>
      </Card>

      {groups.map(g => (
        <Card key={g} pad={0}>
          <div style={{ padding: "15px 20px", borderBottom: "1px solid var(--border)", fontWeight: 600 }}>{g}</div>
          {window.ADMIN_REPORTS.filter(r => r.group === g).map((r, i, arr) => (
            <div key={r.sno} style={{ display: "flex", alignItems: "center", gap: 16, padding: "14px 20px",
              borderBottom: i < arr.length - 1 ? "1px solid var(--border)" : 0 }}>
              <div style={{ width: 36, height: 36, borderRadius: "var(--radius-md)", background: "var(--orange-50)",
                display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}>
                <Icon name="bar-chart-3" size={18} color="var(--orange-900)" /></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14.5, fontWeight: 600 }}>{r.name}</div>
                <div style={{ fontSize: 12.5, color: "var(--fg3)", marginTop: 2 }}>S/No. {r.sno}</div>
              </div>
              <Btn size="sm" variant="secondary" icon="eye" onClick={() => setReport(r)}>Generate</Btn>
            </div>
          ))}
        </Card>
      ))}

      {data && <ReportPreview open={!!report} onClose={() => setReport(null)} report={report}
        columns={data.columns} rows={data.rows} summary={data.summary} />}
    </div>
  );
}

/* Report extracts - S/No. 95-108 */
const ADMIN_REPORT_DATA = {
  "Master transaction report": {
    columns: ["Order", "Buyer", "Partner", "Amount (S$)", "Method", "Status"],
    rows: [["SDC-00482", "Wanderlust Travel", "Multiple (5)", "8,420.00", "PayNow", "Confirmed"],
           ["SDC-00481", "Asia OTA Group", "Sentosa Cable Car", "320.00", "Credit card", "Confirmed"],
           ["SDC-00478", "MICE Connect SG", "Sentosa Cable Car", "4,350.00", "Bank transfer", "Processing"],
           ["SDC-00475", "Island Hoppers", "Sentosa Cable Car", "96.00", "eWallet", "Refunded"],
           ["SDC-00461", "Wanderlust Travel", "Sentosa Islander", "6,960.00", "Bank transfer", "Confirmed"]],
    summary: [["Transactions", "6,412"], ["Gross value", "S$3.38m"], ["Average order", "S$527"]],
  },
  "Commission / incentive tracking report": {
    columns: ["Island partner", "Gross (S$)", "Rate", "Commission (S$)", "Settled (S$)"],
    rows: window.COMMISSION_RULES ? window.COMMISSION_RULES.map(r =>
      [r.partner, (r.ytd / (r.rate / 100)).toLocaleString(undefined, { maximumFractionDigits: 0 }),
       `${r.rate}%`, r.ytd.toLocaleString(), r.ytd.toLocaleString()]) : [],
    summary: [["Commission YTD", "S$734k"], ["Avg rate", "11.5%"], ["Partners", "41"]],
  },
  "Refund tracking report": {
    columns: ["Order", "Buyer", "Amount (S$)", "Reason", "Status"],
    rows: [["SDC-00475", "Island Hoppers", "96.00", "Customer cancellation", "Refunded to eWallet"],
           ["SDC-00440", "Pacific Corporate Travel", "1,240.00", "Weather closure", "Refunded to card"],
           ["SDC-00418", "Asia OTA Group", "384.00", "Duplicate booking", "Refunded to eWallet"]],
    summary: [["Refunds (MTD)", "14"], ["Value", "S$4,820"], ["% of GMV", "0.14%"]],
  },
  "eWallet transaction report": {
    columns: ["Account", "Opening (S$)", "Credits (S$)", "Debits (S$)", "Closing (S$)"],
    rows: [["Wanderlust Travel", "26,400.00", "4,200.00", "6,419.50", "24,180.50"],
           ["Asia OTA Group", "84,200.00", "12,000.00", "18,640.00", "77,560.00"],
           ["MICE Connect SG", "18,900.00", "6,000.00", "9,350.00", "15,550.00"],
           ["Island Hoppers", "4,200.00", "96.00", "1,180.00", "3,116.00"]],
    summary: [["Accounts", "488"], ["Total balance", "S$2.14m"], ["Movements (MTD)", "1,284"]],
  },
  "Account management report": {
    columns: ["Account", "Type", "Tier", "Sub-users", "Volume YTD (S$)"],
    rows: window.ACCOUNTS ? window.ACCOUNTS.map(a => [a.name, a.type, a.tier, String(a.subusers), a.ytd.toLocaleString()]) : [],
    summary: [["Active accounts", "488"], ["Registered", "512"], ["Sub-users", "1,842"]],
  },
  "Account performance report": {
    columns: ["Account", "Orders", "Volume (S$)", "Avg order (S$)", "vs target"],
    rows: [["Asia OTA Group", "412", "986,400", "2,394", "+18%"],
           ["Wanderlust Travel", "268", "412,800", "1,540", "+4%"],
           ["MICE Connect SG", "96", "388,200", "4,044", "+11%"],
           ["Island Hoppers", "142", "142,600", "1,004", "−6%"],
           ["Pacific Corporate Travel", "74", "118,900", "1,607", "−22%"]],
    summary: [["Accounts tracked", "488"], ["Above target", "312"], ["Below target", "176"]],
  },
  "Campaign performance tracking": {
    columns: ["Campaign", "Sent", "Opened", "Converted", "Revenue (S$)"],
    rows: window.CAMPAIGNS ? window.CAMPAIGNS.map(c =>
      [c.name, String(c.sent), String(c.opened), String(c.converted), c.revenue.toLocaleString()]) : [],
    summary: [["Campaigns", "3"], ["Conversions", "69"], ["Attributed revenue", "S$377k"]],
  },
  "Inventory status report": {
    columns: ["Product", "Partner", "Allotment", "Available", "Utilisation"],
    rows: [["Island Admission - Day Pass", "SDC", "40,000", "25,000", "38%"],
           ["Cable Car Sky Pass", "Sentosa Cable Car", "2,500", "1,840", "26%"],
           ["Multi-Attraction Pass (3-in-1)", "Sentosa Islander", "4,000", "3,100", "23%"],
           ["Sky Dining Experience", "Sentosa Cable Car", "400", "64", "84%"],
           ["Cable Car Night Pass", "Sentosa Cable Car", "800", "0", "100%"]],
    summary: [["SKUs live", "312"], ["Low stock", "14"], ["Sold out", "6"]],
  },
  "eTicket tracking report": {
    columns: ["Product", "Issued", "Redeemed", "Unredeemed", "Expired"],
    rows: [["Island Admission - Day Pass", "18,420", "16,104", "2,190", "126"],
           ["Cable Car Sky Pass", "6,284", "5,402", "812", "70"],
           ["Multi-Attraction Pass (3-in-1)", "4,860", "4,014", "798", "48"],
           ["Sky Dining Experience", "642", "561", "81", "0"]],
    summary: [["Issued YTD", "42,180"], ["Redeemed", "36,912"], ["Redemption rate", "87.5%"]],
  },
  "Revalidation tracking report": {
    columns: ["Order", "Buyer", "Tickets", "Fee (S$)", "New expiry"],
    rows: [["SDC-00461", "Wanderlust Travel", "46", "92.00", "24 Jan 2027"],
           ["SDC-00432", "Island Hoppers", "12", "24.00", "18 Dec 2026"],
           ["SDC-00404", "Asia OTA Group", "180", "360.00", "2 Nov 2026"]],
    summary: [["Revalidations (MTD)", "38"], ["Tickets extended", "1,284"], ["Fees collected", "S$2,568"]],
  },
  "Product performance report": {
    columns: ["Product", "Units", "Revenue (S$)", "Conversion", "Trend"],
    rows: [["Island Admission - Day Pass", "18,420", "73,680", "6.8%", "+14%"],
           ["Multi-Attraction Pass (3-in-1)", "4,860", "281,880", "5.1%", "+22%"],
           ["Cable Car Sky Pass", "6,284", "201,088", "4.9%", "+12%"],
           ["Sky Dining Experience", "642", "184,896", "2.2%", "−3%"]],
    summary: [["SKUs", "312"], ["Revenue YTD", "S$3.38m"], ["Top category", "Attraction"]],
  },
  "Product master report": {
    columns: ["SKU", "Product", "Partner", "Trade (S$)", "Status"],
    rows: [["SKU-1042", "Cable Car Sky Pass", "Sentosa Cable Car", "32.00", "Live"],
           ["SKU-1043", "Cable Car + Luge Combo", "Sentosa Cable Car", "48.50", "Live"],
           ["SKU-1051", "Sky Dining Experience", "Sentosa Cable Car", "128.00", "Low stock"],
           ["SKU-1077", "Cable Car Night Pass", "Sentosa Cable Car", "36.00", "Sold out"],
           ["SKU-1104", "Sunset Cabin - Private", "Sentosa Cable Car", "288.00", "In review"]],
    summary: [["Products", "312"], ["Live", "286"], ["In review", "8"]],
  },
  _default: {
    columns: ["Period", "Records", "Value (S$)"],
    rows: [["Jul 2026", "1,284", "612,400"], ["Jun 2026", "1,142", "544,200"], ["May 2026", "998", "478,100"]],
    summary: [["Records", "3,424"], ["Value", "S$1.63m"]],
  },
};

Object.assign(window, { AdminPromotionsScreen, LoyaltyScreen, AccountsScreen, AdminMiceScreen, AdminReportsScreen });

/* ---------------- Payment verification (SDC Finance) ----------------
   S/No. 72  Bank transfer - SDC Finance verifies receipt of funds before approving the transaction
   S/No. 73  Separate invoice template for bank transfer / offline payment
   S/No. 74  Finance reconciliation reporting
   S/No. 117 Payment notification to Sales and Finance
   S/No. 133 Finance is the approving role in the workflow engine
   Reply No. 2 Q20/Q26: tickets are released ONLY on Finance approval. */
function PaymentVerificationScreen({ verified, onVerify }) {
  const [open, setOpen] = React.useState(null);
  const rows = window.PAYMENT_VERIFICATIONS;
  const rec = open ? rows.find(r => r.ref === open) : null;
  const pending = rows.filter(r => !verified[r.ref]).length;

  if (rec) return <PaymentDetail rec={rec} decided={verified[rec.ref]} onBack={() => setOpen(null)} onVerify={onVerify} />;

  return (
    <div style={{ padding: 32, display: "flex", flexDirection: "column", gap: 20 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 12, padding: 16, background: "var(--info-bg)",
        border: "1px solid #c4d4f7", borderRadius: "var(--radius-md)" }}>
        <Icon name="info" size={19} color="#1a44a8" style={{ marginTop: 1 }} />
        <div style={{ fontSize: 13.5, color: "#1a44a8", lineHeight: 1.55 }}>
          Bank transfer is an offline payment method. The buyer uploads proof of payment, Sales and Finance are notified,
          and <strong>eTickets are released only once Finance has matched the funds and approved</strong>. PayNow Dynamic QR
          auto-reconciles and issues immediately, so it carries most local volume - this queue handles the remainder.
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 18 }}>
        <AKpi label="Awaiting verification" value={String(pending)} icon="clock" />
        <AKpi label="Value pending" value="S$15,450" sub="across 3 orders" icon="banknote" />
        <AKpi label="Exceptions" value="1" sub="amount or reference mismatch" icon="alert-triangle" />
        <AKpi label="Auto-matched by reference" value="67%" delta="+12pp" up icon="wand-sparkles" />
      </div>

      <Card pad={0}>
        <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 12 }}>
          <div>
            <div style={{ fontWeight: 600 }}>Bank transfers awaiting Finance approval</div>
            <div className="caption">Matched automatically on the unique payment reference. Exceptions are flagged for manual review.</div>
          </div>
          <div style={{ marginLeft: "auto" }}><ExportButtons name="Finance reconciliation report" rows={rows.length} /></div>
        </div>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 980 }}>
            <thead><tr>
              <th style={ATH}>Reference</th><th style={ATH}>Order</th><th style={ATH}>Buyer</th>
              <th style={{ ...ATH, textAlign: "right" }}>Invoiced</th><th style={{ ...ATH, textAlign: "right" }}>Received</th>
              <th style={ATH}>Match</th><th style={ATH}>Submitted</th><th style={ATH}>Status</th><th style={ATH}></th>
            </tr></thead>
            <tbody>
              {rows.map(r => {
                const st = verified[r.ref] || r.status;
                return (
                  <tr key={r.ref}>
                    <td style={{ ...ATD, fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 13.5 }}>{r.ref}</td>
                    <td style={{ ...ATD, fontFamily: "var(--font-mono)", fontSize: 13.5 }}>{r.order}</td>
                    <td style={{ ...ATD, fontWeight: 600 }}>{r.buyer}</td>
                    <td style={{ ...ATD, textAlign: "right", fontFamily: "var(--font-mono)" }}>S${r.amount.toFixed(2)}</td>
                    <td style={{ ...ATD, textAlign: "right", fontFamily: "var(--font-mono)",
                      color: r.received !== r.amount ? "var(--danger)" : "var(--fg1)",
                      fontWeight: r.received !== r.amount ? 600 : 400 }}>S${r.received.toFixed(2)}</td>
                    <td style={ATD}>{r.matched
                      ? <Badge tone="success">Auto-matched</Badge>
                      : <Badge tone="danger">Needs review</Badge>}</td>
                    <td style={{ ...ATD, color: "var(--fg2)" }}>{r.submitted}</td>
                    <td style={ATD}><Badge tone={tone(st === "Exception" ? "Rejected" : st)}>{st}</Badge></td>
                    <td style={{ ...ATD, textAlign: "right" }}>
                      <button onClick={() => setOpen(r.ref)} style={{ background: "none", border: 0, cursor: "pointer",
                        color: "var(--orange-link)", fontWeight: 600, fontFamily: "var(--font-sans)", fontSize: 14,
                        display: "inline-flex", alignItems: "center", gap: 5 }}>Review<Icon name="chevron-right" size={15} /></button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

function PaymentDetail({ rec, decided, onBack, onVerify }) {
  const [proof, setProof] = React.useState(false);
  const status = decided || rec.status;
  const approved = status === "Approved";
  const variance = rec.received - rec.amount;
  return (
    <div style={{ padding: 32, maxWidth: 1000, margin: "0 auto" }}>
      <button onClick={onBack} style={{ background: "none", border: 0, cursor: "pointer", color: "var(--orange-link)",
        fontWeight: 500, fontFamily: "var(--font-sans)", fontSize: 14, display: "inline-flex", alignItems: "center",
        gap: 6, marginBottom: 18, padding: 0 }}><Icon name="arrow-left" size={16} />Back to payment queue</button>

      <div style={{ display: "flex", alignItems: "flex-start", gap: 16, flexWrap: "wrap", marginBottom: 22 }}>
        <div style={{ flex: 1, minWidth: 260 }}>
          <h2 style={{ margin: 0, fontFamily: "var(--font-mono)" }}>{rec.ref}</h2>
          <div className="caption" style={{ marginTop: 4 }}>Order {rec.order} · {rec.buyer} · submitted {rec.submitted}</div>
        </div>
        <Badge tone={approved ? "success" : rec.matched ? "warning" : "danger"}>{status}</Badge>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 320px", gap: 22, alignItems: "start" }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
          {/* Payment matching */}
          <Card pad={20}>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 4 }}>Payment matching</div>
            <p className="caption" style={{ marginBottom: 16 }}>
              Matched against the unique payment reference issued with the invoice.
            </p>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 14, marginBottom: 16 }}>
              {[["Invoiced", `S$${rec.amount.toFixed(2)}`, null],
                ["Received", `S$${rec.received.toFixed(2)}`, variance !== 0 ? "var(--danger)" : null],
                ["Variance", `${variance >= 0 ? "+" : "−"}S$${Math.abs(variance).toFixed(2)}`, variance !== 0 ? "var(--danger)" : "var(--success)"]].map(([l, v, c]) => (
                <div key={l} style={{ padding: 14, border: "1px solid var(--border)", borderRadius: "var(--radius-md)" }}>
                  <div style={{ fontSize: 12.5, color: "var(--fg2)" }}>{l}</div>
                  <div style={{ fontSize: 20, fontWeight: 700, marginTop: 4, fontFamily: "var(--font-mono)", color: c || "var(--fg1)" }}>{v}</div>
                </div>
              ))}
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: 13,
              background: rec.matched ? "var(--success-bg)" : "var(--danger-bg)", borderRadius: "var(--radius-md)",
              fontSize: 13.5, color: rec.matched ? "#0f5e35" : "#8f1c17", lineHeight: 1.5 }}>
              <Icon name={rec.matched ? "check-circle" : "alert-triangle"} size={17} style={{ flex: "none" }} />
              {rec.matched
                ? <span>Reference <strong style={{ fontFamily: "var(--font-mono)" }}>{rec.bankRef}</strong> matched automatically. Amount reconciles exactly.</span>
                : <span>{rec.note}</span>}
            </div>
          </Card>

          {/* Proof of payment */}
          <Card pad={20}>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 4 }}>Proof of payment</div>
            <p className="caption" style={{ marginBottom: 14 }}>Uploaded by the buyer at checkout. Sales and Finance were notified on submission.</p>
            <div style={{ display: "flex", alignItems: "center", gap: 11, padding: "12px 14px",
              border: "1px solid var(--border)", borderRadius: "var(--radius-md)" }}>
              <Icon name="file-text" size={18} color="var(--fg2)" />
              <span style={{ flex: 1, fontSize: 14, fontWeight: 600 }}>{rec.proof}</span>
              <Btn size="sm" variant="secondary" icon="eye" onClick={() => setProof(true)}>View</Btn>
            </div>
          </Card>

          {/* Release chain */}
          <Card pad={20}>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 4 }}>Ticket release</div>
            <p className="caption" style={{ marginBottom: 16 }}>
              {rec.tickets} eTickets are held until Finance approves. Nothing is issued on receipt of funds alone.
            </p>
            <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
              {[["Buyer submitted order with proof of payment", true],
                ["Sales and Finance notified", true],
                ["Finance matched and approved the payment", approved],
                [`${rec.tickets} eTickets released to the buyer organisation`, approved]].map(([label, done], i, arr) => (
                <div key={label} style={{ display: "flex", gap: 12 }}>
                  <div style={{ display: "flex", flexDirection: "column", alignItems: "center", flex: "none" }}>
                    <span style={{ width: 20, height: 20, borderRadius: 999, display: "flex", alignItems: "center", justifyContent: "center",
                      background: done ? "var(--success)" : "var(--neutral-100)", border: done ? 0 : "1.5px solid var(--border-strong)" }}>
                      {done && <Icon name="check" size={12} color="#fff" strokeWidth={3} />}
                    </span>
                    {i < arr.length - 1 && <span style={{ width: 2, flex: 1, minHeight: 18, background: "var(--border)" }}></span>}
                  </div>
                  <div style={{ paddingBottom: i < arr.length - 1 ? 14 : 0, fontSize: 14,
                    fontWeight: done ? 600 : 500, color: done ? "var(--fg1)" : "var(--fg2)" }}>{label}</div>
                </div>
              ))}
            </div>
          </Card>
        </div>

        <Card pad={20} style={{ position: "sticky", top: 88 }}>
          <div style={{ fontWeight: 600, fontSize: 15, marginBottom: 14 }}>Finance decision</div>
          {approved ? (
            <div style={{ display: "flex", gap: 10, padding: 14, background: "var(--success-bg)", borderRadius: "var(--radius-md)",
              fontSize: 13.5, color: "#0f5e35", lineHeight: 1.5 }}>
              <Icon name="check-circle" size={17} style={{ marginTop: 1, flex: "none" }} />
              Payment verified. {rec.tickets} eTickets have been released to {rec.buyer} and the transaction is posted to the financial sub-ledger.
            </div>
          ) : (
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <Btn variant="primary" full icon="check" onClick={() => { onVerify(rec.ref, "Approved");
                window.toast("Payment verified", "success", `${rec.tickets} eTickets released to ${rec.buyer}`); }}>
                Approve &amp; release tickets
              </Btn>
              <Btn variant="secondary" full icon="message-square"
                onClick={() => window.toast("Query sent to buyer", "info", `${rec.buyer} asked to clarify the shortfall`)}>Query with buyer</Btn>
              <Btn variant="ghost" full icon="x" onClick={() => { onVerify(rec.ref, "Rejected");
                window.toast("Payment rejected", "warning", "Buyer notified · order returned to unpaid"); }}>Reject</Btn>
            </div>
          )}
          <p className="caption" style={{ marginTop: 14, marginBottom: 0 }}>
            Approving officer and timestamp are written to the audit trail and the Finance reconciliation report.
          </p>
        </Card>
      </div>

      <DocPreview open={proof} onClose={() => setProof(false)} title={rec.proof} kind="Proof of payment"
        meta={[["Buyer", rec.buyer], ["Order", rec.order], ["Reference quoted", rec.bankRef],
               ["Amount received", `S$${rec.received.toFixed(2)}`]]} />
    </div>
  );
}

Object.assign(window, { PaymentVerificationScreen, PaymentDetail });
