// =================================================================
// pw-screens-partners.jsx — Channel partners (migration 0066).
//
// A publisher that brings a client (a brand that registers through its advertiser portal) is that
// client's channel partner. On the partner's own site the client pays the own rate (90/10). On any
// other publisher's site the host keeps its normal share and the partner earns a fee out of DropCap's
// share — 10% by default: host 72 / DropCap 18 / partner 10.
//
//   OpPartnerFeesScreen     operator: the default fee and per-partner overrides. Any staff reads;
//                           only a full-scope superadmin writes (the API refuses a manager with 403).
//   PartnerFeeCreateScreen  operator: set a fee. Never edits — a new row takes over from its date,
//                           and every event already billed keeps the fee it was billed at.
//   PartnerEarningsScreen   publisher: what it has earned per client it brought.
// =================================================================

const partnerNotify = (msg, tone) => (window.__toast ? window.__toast(msg, tone) : null);
const PF_STATE_TONE = { in_force: "good", scheduled: "accent", superseded: "neutral" };
const pfPct = (bps) => (bps === null || bps === undefined ? "—" : `${(Number(bps) / 100).toFixed(Number(bps) % 100 ? 2 : 0)}%`);
const pfMinor = (minor, currency) => fmt.currency(Number(minor || 0) / 100, currency || "USD");

const OpPartnerFeesScreen = ({ data }) => {
  const rates = useListQuery("adminListPartnerFeeRates", { sort: "effective_from", dir: "desc", filters: { kind: "", status: "" }, watch: data.partnerFeeRates });
  React.useEffect(() => { if (rates.error) partnerNotify("Could not load partner fees.", "bad"); }, [rates.error]);
  const def = (rates.extra && rates.extra.default_in_force)
    || (data.partnerFeeRates || []).find((r) => r.kind === "default" && r.status === "in_force");
  return (
    <Screen>
      <PageHead icon={IconUsers} title="Partner fees"
        subtitle="What a publisher earns when a client it brought runs on another publisher's site. Paid from DropCap's share; the host keeps its normal share."
        actions={<Btn kind="primary" size="sm" onClick={() => window.__nav("partner-fee-create")}>Set a fee</Btn>}/>
      <Banner tone="info" icon={<IconInfo size={15}/>}>
        Superadmin only: managers can view fees but cannot change them. A fee is never edited — a new one takes over from its
        effective date, and every click or conversion already billed keeps the fee it was billed at. On the partner's own site the
        client pays the own rate (90 / 10) and no partner fee applies. CPC and CPA only.
      </Banner>
      <KpiGrid>
        <StatCard label="Default partner fee" value={def ? pfPct(def.fee_bps) : "—"} sub={def ? `host 72% · DropCap ${pfPct(2800 - def.fee_bps)} at today's direct rate` : "No default in force"}/>
        <StatCard label="Overrides" value={fmt.number((rates.rows || []).filter((r) => r.kind === "override" && r.status !== "superseded").length)} sub="in force or scheduled (this page)"/>
      </KpiGrid>
      <Card title="Fees" subtitle="The default, and partners on their own fee." padded={false}>
        <div style={{ padding: "12px 16px", borderBottom: "1px solid var(--line-2)" }}>
          <ListToolbar list={rates} placeholder="Search partner or note"
            filters={[
              { key: "kind", label: "Kinds", options: [{ label: "Default", value: "default" }, { label: "Override", value: "override" }] },
              { key: "status", label: "States", options: statusOptions(["in_force", "scheduled", "superseded"]) },
            ]}/>
        </div>
        <DataTable rows={rates.rows} keyField="rate_id" server={rates.server} empty="No fees match."
          columns={[
            { key: "partner_name", label: "Applies to", sortable: true, render: (r) => r.kind === "default"
              ? <strong style={{ color: "var(--ink)" }}>Every partner (default)</strong> : (r.partner_name || r.partner_publisher_id) },
            { key: "fee_bps", label: "Partner earns", sortable: true, align: "right", render: (r) => r.fee_bps === null
              ? <span style={{ color: "var(--muted)" }}>back to default</span> : <strong>{pfPct(r.fee_bps)}</strong> },
            { key: "effective_from", label: "From", sortable: true, render: (r) => <span style={{ fontFamily: "var(--mono)", fontSize: 12.5 }}>{fmt.date(r.effective_from)}</span> },
            { key: "status", label: "State", render: (r) => <Pill tone={PF_STATE_TONE[r.status] || "neutral"}>{String(r.status || "").replace("_", " ")}</Pill> },
            { key: "note", label: "Note", render: (r) => <span style={{ fontSize: 12.5, color: "var(--muted)" }}>{r.note || ""}</span> },
          ]}/>
      </Card>
    </Screen>
  );
};

const PartnerFeeCreateScreen = ({ data }) => {
  useRefList(["listPublishers"]);
  const [f, setF] = React.useState({ partner_publisher_id: "", mode: "rate", fee: "", effective_from: "", note: "" });
  const [busy, setBusy] = React.useState(false);
  const set = (p) => setF((x) => ({ ...x, ...p }));
  const pubs = data.publishers || [];
  const pct = f.fee === "" ? NaN : Number(f.fee);
  const backToDefault = f.partner_publisher_id && f.mode === "default";
  // The database refuses a fee above DropCap's direct share (28% today); the form says so first.
  const rateOk = backToDefault || (pct >= 0 && pct <= 28);
  const future = f.effective_from ? new Date(f.effective_from) : null;
  const dateOk = !future || future.getTime() >= Date.now() - 60_000;
  const canSave = rateOk && dateOk && f.note.trim() && !busy;
  const save = async () => {
    setBusy(true);
    const fee_bps = backToDefault ? null : Math.round(pct * 100);
    const body = {
      ...(f.partner_publisher_id ? { partner_publisher_id: f.partner_publisher_id } : {}),
      fee_bps,
      ...(future ? { effective_from: future.toISOString() } : {}),
      note: f.note.trim(),
    };
    const eff = future ? future.toISOString() : new Date().toISOString();
    const scheduled = Boolean(future && future.getTime() > Date.now());
    const pub = pubs.find((p) => (p.publisher_id || p.id) === f.partner_publisher_id);
    const row = { rate_id: "pf_" + Math.random().toString(36).slice(2, 8), kind: f.partner_publisher_id ? "override" : "default", partner_publisher_id: f.partner_publisher_id || null,
      partner_name: pub ? pub.name : null, fee_bps, effective_from: eff, superseded_at: null, status: scheduled ? "scheduled" : "in_force",
      note: body.note, created_by: "you", created_at: new Date().toISOString() };
    const same = (r) => (r.partner_publisher_id || null) === row.partner_publisher_id;
    try {
      await window.__api.write("adminCreatePartnerFeeRate",
        (d) => ({ ...d, partnerFeeRates: [row, ...(d.partnerFeeRates || []).map((r) => (!scheduled && r.status === "in_force" && same(r) ? { ...r, status: "superseded", superseded_at: eff } : r))] }),
        { body, ok: scheduled ? "Fee scheduled" : "Fee in force", err: "Couldn’t set that fee" });
      pwListsStale();
      window.__nav("op-partner-fees");
    } catch (e) { /* write() has already said why */ } finally { setBusy(false); }
  };
  return (
    <FormFrame page={{ icon: IconUsers, back: "Partner fees" }} kind="modal" open onClose={pwBackTo("op-partner-fees")} title="Set a partner fee" width={520}
      footer={<><Btn kind="secondary" onClick={pwBackTo("op-partner-fees")}>Cancel</Btn><Btn kind="primary" disabled={!canSave} onClick={save}>{busy ? "Saving…" : "Save fee"}</Btn></>}>
      <FormField label="Applies to" hint="Blank sets the default for every partner; choosing a publisher sets its own fee.">
        <Select value={f.partner_publisher_id} onChange={(v) => set({ partner_publisher_id: v, mode: "rate" })}
          options={[{ label: "Every partner (default)", value: "" }, ...pubs.map((p) => ({ label: p.name, value: p.publisher_id || p.id }))]}/>
      </FormField>
      {f.partner_publisher_id && (
        <FormField label="Fee">
          <SegmentedControl value={f.mode} onChange={(v) => set({ mode: v })}
            options={[{ label: "Own fee", value: "rate" }, { label: "Back to the default", value: "default" }]}/>
        </FormField>
      )}
      {!backToDefault && (
        <FormField label="Partner earns (%)" hint={Number.isFinite(pct) && rateOk ? `Of each click or conversion on another publisher. DropCap keeps ${(28 - pct).toFixed(2).replace(/\.00$/, "")}% at today's direct rate; the host's 72% is unchanged.` : "Between 0 and 28 (DropCap's direct share)."}>
          <Input type="number" step="0.01" min="0" max="28" value={f.fee} placeholder="10" onChange={(e) => set({ fee: e.target.value })}/>
        </FormField>
      )}
      <FormField label="Effective from" hint="Blank: now. Never in the past — events already billed keep their fee either way.">
        <Input type="datetime-local" value={f.effective_from} onChange={(e) => set({ effective_from: e.target.value })}/>
      </FormField>
      <FormField label="Note" hint="Why — recorded with the fee and in the audit trail.">
        <Input value={f.note} maxLength={500} onChange={(e) => set({ note: e.target.value })}/>
      </FormField>
      {!dateOk && <div style={{ fontSize: 12.5, color: "var(--bad)" }}>Effective date is in the past.</div>}
    </FormFrame>
  );
};

const PartnerEarningsScreen = ({ data }) => {
  const [state, setState] = React.useState({ loading: true, earnings: null });
  React.useEffect(() => {
    let off = false;
    window.__api.read("getPartnerEarnings")
      .then((e) => { if (!off) setState({ loading: false, earnings: e || data.partnerEarnings || null }); })
      .catch(() => { if (!off) { setState({ loading: false, earnings: null }); partnerNotify("Could not load partner earnings.", "bad"); } });
    return () => { off = true; };
  }, []);
  const e = state.earnings;
  const clients = (e && e.clients) || [];
  const totals = {};
  for (const c of clients) {
    if (!c.currency) continue;
    if (!totals[c.currency]) totals[c.currency] = { fee: 0, held: 0, paid: 0 };
    const t = totals[c.currency];
    t.fee += Number(c.fee_minor || 0); t.held += Number(c.held_minor || 0); t.paid += Number(c.paid_minor || 0);
  }
  const main = Object.keys(totals)[0] || "USD";
  return (
    <Screen>
      <PageHead icon={IconUsers} title="Partner earnings"
        subtitle="Clients you brought to DropCap. When they run on another publisher's site you earn a fee on every click or conversion — for as long as they advertise."/>
      <Banner tone="info" icon={<IconInfo size={15}/>}>
        On your own site your clients pay the own rate: you keep 90%. Elsewhere the host keeps its normal share and your fee comes out
        of DropCap's. Fees are held like your other earnings and paid on your normal statement, as a "Partner fee" line.
      </Banner>
      <KpiGrid>
        <StatCard label="Your fee" value={e && e.fee_in_force ? pfPct(e.fee_in_force.fee_bps) : "—"} sub={e && e.fee_in_force ? (e.fee_in_force.source === "partner" ? "your negotiated fee" : "the standard fee") : ""}/>
        <StatCard label="Clients" value={fmt.number(new Set(clients.map((c) => c.advertiser_id)).size)} sub="brought by you"/>
        <StatCard label="Earned" value={pfMinor(totals[main]?.fee, main)} sub={`${pfMinor(totals[main]?.held, main)} held · ${pfMinor(totals[main]?.paid, main)} paid`}/>
      </KpiGrid>
      <Card title="By client" subtitle="Net of any disputed conversions." padded={false}>
        <DataTable rows={clients.map((c, i) => ({ ...c, _k: `${c.advertiser_id}-${c.currency || i}` }))} keyField="_k"
          empty={state.loading ? "Loading…" : "No clients yet. Brands that register through your advertiser portal appear here."}
          columns={[
            { key: "advertiser_name", label: "Client", render: (r) => <span>{r.advertiser_name || r.advertiser_id}{!r.introduced && <span style={{ color: "var(--muted)", fontSize: 11.5 }}> · reassigned</span>}</span> },
            { key: "events", label: "Billed events", align: "right", render: (r) => fmt.number(r.events) },
            { key: "fee_minor", label: "Earned", align: "right", render: (r) => r.currency ? pfMinor(r.fee_minor, r.currency) : "—" },
            { key: "held_minor", label: "Held", align: "right", render: (r) => r.currency ? pfMinor(r.held_minor, r.currency) : "—" },
            { key: "available_minor", label: "Matured", align: "right", render: (r) => r.currency ? pfMinor(r.available_minor, r.currency) : "—" },
            { key: "paid_minor", label: "Paid", align: "right", render: (r) => r.currency ? pfMinor(r.paid_minor, r.currency) : "—" },
          ]}/>
      </Card>
    </Screen>
  );
};

Object.assign(window, { OpPartnerFeesScreen, PartnerFeeCreateScreen, PartnerEarningsScreen });
