/* global React */

// Fake backend — simulates the loop "Nudge recommends → user sends → buyer
// replies → deal state moves". Records live in memory; seed deal data is
// never mutated. Components read augmented state via applyImpact() (one
// shot) or useNudgeImpact() (subscribed). Two execution paths feed this:
// the home-page priority card's `commit` in fireAction, and the deal-room
// AI Actions tab's onSend. Both call execute() with a normalised payload.

(function () {
  const state = {
    actions: {},      // dealId -> [record]
    listeners: new Set(),
  };

  const REPLY_DELAY_MS = 5200;

  function notify() {
    state.listeners.forEach((fn) => { try { fn(); } catch (_) {} });
  }

  function uid() {
    return `nb-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
  }

  // Severity-tier impact model — matches the pre-execution math in
  // screens-home.jsx so the post-execution numbers stay credible. A 50pt
  // gap doesn't close in one nudge; a 12pt gap can.
  function projectImpact(gapBefore) {
    if (gapBefore >= 25) return Math.max(4, Math.round(gapBefore * 0.30));
    if (gapBefore >= 10) return Math.max(3, Math.round(gapBefore * 0.55));
    return Math.max(2, Math.round(gapBefore * 0.40));
  }

  function execute(deal, payload = {}) {
    if (!deal || !deal.id) return null;
    const dealId = deal.id;
    const gapBefore = Math.abs(deal.gap || 0);
    const buyerBefore = deal.buyerScore || 0;
    const sellerBefore = deal.sellerScore || 0;
    const gapReduction = projectImpact(gapBefore);
    const gapAfter = Math.max(0, gapBefore - gapReduction);
    const buyerAfter = Math.min(100, buyerBefore + gapReduction);

    const record = {
      id: uid(),
      dealId,
      recommendedBy: "nudge",
      kind: payload.kind || "Recommended action",
      channel: payload.channel || null,
      recipient: payload.recipient || null,
      action: payload.action || `Action on ${deal.company || "deal"}`,
      subject: payload.subject || null,
      body: payload.body || payload.text || null,
      replyPreview: payload.outcome || null,
      sentAt: new Date(),
      status: "sent",
      gapBefore,
      gapAfter,
      gapDelta: -gapReduction,
      buyerBefore,
      buyerAfter,
      sellerBefore,
      sellerAfter: sellerBefore,
    };

    (state.actions[dealId] = state.actions[dealId] || []).push(record);
    notify();

    // Buyer reply — flips status, applyImpact then folds the gap delta into
    // the overlay so the BSP bar, tone wash, and verdict line all recalc.
    setTimeout(() => {
      record.status = "replied";
      record.repliedAt = new Date();
      notify();
    }, REPLY_DELAY_MS);

    return record;
  }

  function getActions(dealId) {
    return state.actions[dealId] || [];
  }

  // Read-time overlay — deal goes in, "as if all replied nudge actions had
  // happened" deal comes out. Original seed is never touched.
  function applyImpact(deal) {
    if (!deal || !deal.id) return deal;
    const actions = state.actions[deal.id] || [];
    const replied = actions.filter((a) => a.status === "replied");
    if (replied.length === 0) return deal;
    const totalGapReduction = replied.reduce((sum, a) => sum + Math.abs(a.gapDelta || 0), 0);
    const totalBuyerLift = replied.reduce((sum, a) => sum + ((a.buyerAfter - a.buyerBefore) || 0), 0);
    const originalGap = deal.gap != null ? deal.gap : 0;
    const sign = originalGap < 0 ? -1 : 1;
    const newGapAbs = Math.max(0, Math.abs(originalGap) - totalGapReduction);
    const newBuyer = Math.min(100, (deal.buyerScore || 0) + totalBuyerLift);
    let nextStatus = deal.status;
    let nextStatusLabel = deal.statusLabel;
    if (newGapAbs < 10 && deal.status !== "healthy") {
      nextStatus = "healthy";
      nextStatusLabel = "Healthy";
    } else if (newGapAbs < 25 && deal.status === "at-risk") {
      nextStatus = "needs-attention";
      nextStatusLabel = "Watch";
    }
    return {
      ...deal,
      gap: newGapAbs * sign,
      buyerScore: newBuyer,
      status: nextStatus,
      statusLabel: nextStatusLabel,
      nudgeImpact: {
        totalGapReduction,
        totalBuyerLift,
        actionCount: replied.length,
        actions: replied,
      },
    };
  }

  function applyImpactToList(deals) {
    return (deals || []).map(applyImpact);
  }

  function subscribe(fn) {
    state.listeners.add(fn);
    return () => state.listeners.delete(fn);
  }

  // Hook variants — each subscribes for the component's lifetime and
  // returns the overlaid deal/list. Components don't need to know about
  // the listener wiring.
  function useNudgeImpact(deal) {
    const [, force] = React.useState(0);
    React.useEffect(() => {
      const unsub = subscribe(() => force((n) => n + 1));
      return unsub;
    }, [deal && deal.id]);
    return applyImpact(deal);
  }

  function useNudgeImpactList(deals) {
    const [, force] = React.useState(0);
    React.useEffect(() => {
      const unsub = subscribe(() => force((n) => n + 1));
      return unsub;
    }, []);
    return applyImpactToList(deals);
  }

  window.NudgeBackend = {
    execute,
    getActions,
    applyImpact,
    applyImpactToList,
    subscribe,
    useNudgeImpact,
    useNudgeImpactList,
  };
})();
