// BILLING & ANALYTICS STORE — mutable state, pub/sub, APIs
(function () {
  const clone = (x) => JSON.parse(JSON.stringify(x));
  const seed = window.BILLING_ANALYTICS_DATA || {};

  const state = {
    passiveCapture:      clone(seed.passiveCapture || []),
    ocgRules:            clone(seed.ocgRules || []),
    ocgViolations:       clone(seed.ocgViolations || []),
    narrativeFlags:      clone(seed.narrativeFlags || []),
    rateCards:           clone(seed.rateCards || []),
    rateChangeRequests:  clone(seed.rateChangeRequests || []),
    rateRaiseScenarios:  clone(seed.rateRaiseScenarios || []),
    pricingBenchmarks:   clone(seed.pricingBenchmarks || []),
    preBillIssues:       clone(seed.preBillIssues || []),
    ebillingVendors:     clone(seed.ebillingVendors || []),
    ebillingSubmissions: clone(seed.ebillingSubmissions || []),
    jointMatters:        clone(seed.jointMatters || []),
    arPredictions:       clone(seed.arPredictions || []),
    wipRisk:             clone(seed.wipRisk || []),
    budgetPacing:        clone(seed.budgetPacing || []),
    realizationWaterfall: clone(seed.realizationWaterfall || []),
    matterProfitability: clone(seed.matterProfitability || []),
    clientProfitabilityDecile: clone(seed.clientProfitabilityDecile || []),
    partnerBook:         clone(seed.partnerBook || []),
    industryBenchmarks:  clone(seed.industryBenchmarks || []),
    churnRisk:           clone(seed.churnRisk || []),
    warRoomKPIs:         clone(seed.warRoomKPIs || {}),
    auditLog:            [],
  };

  const bus = {
    _subs: {},
    on(topic, fn) {
      (this._subs[topic] = this._subs[topic] || []).push(fn);
      return () => { this._subs[topic] = (this._subs[topic] || []).filter(f => f !== fn); };
    },
    emit(topic, data) {
      (this._subs[topic] || []).forEach(fn => { try { fn(data); } catch (e) { console.error(e); } });
      (this._subs['*'] || []).forEach(fn => { try { fn({ topic, data }); } catch (e) { console.error(e); } });
      try { window.dispatchEvent(new CustomEvent('arbiter:ba.' + topic, { detail: data })); } catch {}
    },
  };

  const audit = (action, user, detail, ref) => {
    const entry = { ts: new Date().toISOString(), user: user || 'System', action, detail: detail || '', ref: ref || null };
    state.auditLog.unshift(entry);
    bus.emit('audit.logged', entry);
    return entry;
  };

  // ── 1. Passive Time Capture ──
  const approvePassiveEntry = (id, user) => {
    const e = state.passiveCapture.find(x => x.id === id);
    if (!e) return null;
    e.status = 'approved';
    audit('passive.approved', user, `Approved ${e.hours}h on ${e.matter}`, id);
    bus.emit('passive.approved', e);
    return e;
  };
  const rejectPassiveEntry = (id, user) => {
    const e = state.passiveCapture.find(x => x.id === id);
    if (!e) return null;
    e.status = 'rejected';
    audit('passive.rejected', user, `Rejected ${e.hours}h signal from ${e.source}`, id);
    bus.emit('passive.rejected', e);
    return e;
  };
  const approveAllPassive = (user) => {
    const pending = state.passiveCapture.filter(e => e.status === 'pending');
    pending.forEach(e => { e.status = 'approved'; });
    audit('passive.bulk-approved', user, `Bulk-approved ${pending.length} entries`);
    bus.emit('passive.bulk-approved', { count: pending.length });
    return pending.length;
  };

  // ── 2. OCG Violations ──
  const resolveOcgViolation = (id, action, user) => {
    const v = state.ocgViolations.find(x => x.id === id);
    if (!v) return null;
    v.status = 'resolved';
    v.resolution = action;
    audit('ocg.resolved', user, `${v.rule} via ${action}`, id);
    bus.emit('ocg.resolved', v);
    return v;
  };

  // ── 3. Narrative rewrite accept ──
  const acceptNarrativeRewrite = (id, user) => {
    const n = state.narrativeFlags.find(x => x.id === id);
    if (!n) return null;
    n.accepted = true;
    audit('narrative.rewritten', user, `Applied suggested rewrite for ${n.entryId}`, id);
    bus.emit('narrative.rewritten', n);
    return n;
  };

  // ── 4. Rate Card change approval ──
  const approveRateChange = (id, user) => {
    const r = state.rateChangeRequests.find(x => x.id === id);
    if (!r) return null;
    r.status = 'approved';
    audit('rate.approved', user, `${r.proposal} approved for ${r.rateCard}`, id);
    bus.emit('rate.approved', r);
    return r;
  };

  // ── 7. Pre-Bill issue resolve ──
  const resolvePreBillIssue = (id, outcome, user) => {
    const issue = state.preBillIssues.find(x => x.id === id);
    if (!issue) return null;
    issue.status = 'resolved';
    issue.outcome = outcome;
    audit('prebill.resolved', user, `${issue.type} → ${outcome}`, id);
    bus.emit('prebill.resolved', issue);
    return issue;
  };
  const bulkResolvePreBill = (ids, outcome, user) => {
    const resolved = [];
    ids.forEach(id => {
      const issue = state.preBillIssues.find(x => x.id === id);
      if (issue) { issue.status = 'resolved'; issue.outcome = outcome; resolved.push(issue); }
    });
    audit('prebill.bulk-resolved', user, `${resolved.length} issues → ${outcome}`);
    bus.emit('prebill.bulk-resolved', { count: resolved.length, outcome });
    return resolved.length;
  };

  // ── 8. eBilling appeal / retry ──
  const appealEbillingReduction = (id, user) => {
    const s = state.ebillingSubmissions.find(x => x.id === id);
    if (!s) return null;
    s.status = 'Appealed';
    s.appealedBy = user;
    s.appealedAt = new Date().toISOString().slice(0, 10);
    audit('ebilling.appealed', user, `Appeal filed for ${s.invoice}`, id);
    bus.emit('ebilling.appealed', s);
    return s;
  };

  // ── 10. AR collection action ──
  const triggerCollectionAction = (client, action, user) => {
    const ar = state.arPredictions.find(x => x.client === client);
    if (!ar) return null;
    ar.lastAction = action;
    ar.lastActionAt = new Date().toISOString().slice(0, 10);
    audit('collection.triggered', user, `${action} on ${client}`, client);
    bus.emit('collection.triggered', { client, action });
    return ar;
  };

  // ── 12. Budget escalation ──
  const escalateBudgetAlert = (matter, user) => {
    const b = state.budgetPacing.find(x => x.matter === matter);
    if (!b) return null;
    b.escalated = true;
    audit('budget.escalated', user, `${matter} escalated — ${b.varPct}% variance`, matter);
    bus.emit('budget.escalated', b);
    return b;
  };

  // ── 15. Partner flight-risk mitigation ──
  const flagPartnerRetention = (partner, note, user) => {
    const p = state.partnerBook.find(x => x.partner === partner);
    if (!p) return null;
    p.retentionFlag = { note, flaggedBy: user, flaggedAt: new Date().toISOString().slice(0, 10) };
    audit('retention.flagged', user, `${partner} flagged for retention review`, partner);
    bus.emit('retention.flagged', p);
    return p;
  };

  // ── 17. Churn response ──
  const triggerChurnResponse = (client, action, user) => {
    const c = state.churnRisk.find(x => x.client === client);
    if (!c) return null;
    c.response = { action, takenBy: user, takenAt: new Date().toISOString().slice(0, 10) };
    audit('churn.response', user, `${client}: ${action}`, client);
    bus.emit('churn.response', c);
    return c;
  };

  // ── Cross-platform bridges ──
  // Push a matter to Rulebook (e.g. "deadline-regulate fees against a rule")
  const pushRuleReference = ({ ruleId, matter, reason }) => {
    const entry = { source: 'billing', ruleId, matter, reason, ts: new Date().toISOString() };
    audit('rulebook.push', 'System', `→ Rulebook: ${ruleId} for ${matter}`);
    bus.emit('rulebook.push', entry);
    try { window.dispatchEvent(new CustomEvent('arbiter:ba.rulebook.push', { detail: entry })); } catch {}
    return entry;
  };
  // Push a collection deadline to Calendar
  const pushCollectionToCalendar = ({ client, dueDate, priority, notes }) => {
    const entry = { source: 'billing', client, dueDate, priority: priority || 'high', notes: notes || '', ts: new Date().toISOString() };
    audit('calendar.push', 'System', `→ Calendar: collection for ${client} on ${dueDate}`);
    bus.emit('calendar.push', entry);
    try { window.dispatchEvent(new CustomEvent('arbiter:ba.calendar.push', { detail: entry })); } catch {}
    return entry;
  };

  // Listen for cross-platform signals
  window.addEventListener('arbiter:matter.opened', (ev) => {
    bus.emit('matter.focus', ev.detail || {});
  });
  window.addEventListener('arbiter:rk.incident.logged', (ev) => {
    const d = ev.detail || {};
    if (d.financialImpact) audit('risk.financial', 'System', `Risk incident with financial impact: ${d.financialImpact}`);
  });

  // ── Aggregations ──
  const passivePending = () => state.passiveCapture.filter(e => e.status === 'pending');
  const passivePendingValue = () => passivePending().reduce((s, e) => s + (e.hours * 1200), 0);
  const ocgOpenCount = () => state.ocgViolations.filter(v => v.status === 'flagged').length;
  const ocgOpenValue = () => state.ocgViolations.filter(v => v.status === 'flagged').reduce((s, v) => s + v.value, 0);
  const preBillOpenCount = () => state.preBillIssues.filter(i => i.status !== 'resolved').length;
  const preBillOpenValue = () => state.preBillIssues.filter(i => i.status !== 'resolved').reduce((s, i) => s + i.value, 0);
  const budgetAlertsCount = () => state.budgetPacing.filter(b => b.alertLevel === 'crimson' || b.alertLevel === 'amber').length;
  const highChurnClients = () => state.churnRisk.filter(c => c.churnProb >= 0.3);
  const totalRevenueAtRisk = () => state.churnRisk.reduce((s, c) => s + c.revenueAtRisk, 0);

  const API = {
    state, bus, audit,
    approvePassiveEntry, rejectPassiveEntry, approveAllPassive,
    resolveOcgViolation,
    acceptNarrativeRewrite,
    approveRateChange,
    resolvePreBillIssue, bulkResolvePreBill,
    appealEbillingReduction,
    triggerCollectionAction,
    escalateBudgetAlert,
    flagPartnerRetention,
    triggerChurnResponse,
    pushRuleReference, pushCollectionToCalendar,
    passivePending, passivePendingValue, ocgOpenCount, ocgOpenValue,
    preBillOpenCount, preBillOpenValue, budgetAlertsCount,
    highChurnClients, totalRevenueAtRisk,
  };

  window.BillingAnalyticsStore = API;

  window.useBillingAnalyticsStore = (topics) => {
    const topicList = Array.isArray(topics) ? topics : [topics || '*'];
    const [, force] = React.useReducer(x => x + 1, 0);
    React.useEffect(() => {
      const offs = topicList.map(t => bus.on(t, () => force()));
      return () => offs.forEach(off => off());
    }, []);
    return state;
  };
})();
