/* ═══════════════════════════════════════════════════════════════
   PROPOSAL CART — shared state consumed by Scanner (produces items),
   Estimator (builds quote), and Proposal (generates deliverable).

   Persists in localStorage under 'wpsb:proposal-cart' so it survives
   refresh and is visible across pages.

   Shape:
   {
     items: [
       { id, source, category, label, description, scope, lowPrice,
         highPrice, hours, priority, dependencies, clientNotes,
         internalNotes, included, recurring }
     ],
     narrative: { frameworkStake, approachStake, timelineStake },
     evidenceEmbedded: true,
     tokens: { site, violations, deadline, taxonomy, legalFramework, score },
   }
   ═══════════════════════════════════════════════════════════════ */

(function() {
  const STORAGE_KEY = 'wpsb:proposal-cart';

  const DEFAULT = {
    items: [],
    narrative: {
      frameworkStake: '',
      approachStake: '',
      timelineStake: '',
    },
    evidenceEmbedded: true,
    tokens: {
      site: '', violations: 0, deadline: '', taxonomy: '',
      legalFramework: '', score: 0, pagesScanned: 0, pdfsFound: 0,
    },
  };

  function load() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (!raw) return { ...DEFAULT };
      const parsed = JSON.parse(raw);
      return { ...DEFAULT, ...parsed };
    } catch(e) {
      return { ...DEFAULT };
    }
  }

  function save(state) {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
      // Notify listeners in this window
      window.dispatchEvent(new CustomEvent('wpsb:cart-changed', { detail: state }));
    } catch(e) { /* quota, private mode — no-op */ }
  }

  const ProposalCart = {
    get() { return load(); },

    addItem(item) {
      const state = load();
      const id = item.id || `CART-${Date.now()}-${Math.random().toString(36).slice(2,6)}`;
      // Dedupe: if an item with same label+source exists, update it
      const existingIdx = state.items.findIndex(i => i.label === item.label && i.source === item.source);
      const full = {
        id, source: 'ada-scan', category: 'remediation',
        description: '', scope: '', lowPrice: 0, highPrice: 0,
        hours: null, priority: 'medium', dependencies: '',
        clientNotes: '', internalNotes: '', included: true, recurring: null,
        ...item,
      };
      if (existingIdx >= 0) state.items[existingIdx] = full;
      else state.items.push(full);
      save(state);
      return full;
    },

    addItems(items) {
      items.forEach(i => this.addItem(i));
    },

    updateItem(id, updates) {
      const state = load();
      const idx = state.items.findIndex(i => i.id === id);
      if (idx >= 0) {
        state.items[idx] = { ...state.items[idx], ...updates };
        save(state);
      }
    },

    removeItem(id) {
      const state = load();
      state.items = state.items.filter(i => i.id !== id);
      save(state);
    },

    clear() { save({ ...DEFAULT }); },

    setTokens(tokens) {
      const state = load();
      state.tokens = { ...state.tokens, ...tokens };
      save(state);
    },

    setNarrative(narrative) {
      const state = load();
      state.narrative = { ...state.narrative, ...narrative };
      save(state);
    },

    getBySource(source) {
      return load().items.filter(i => i.source === source);
    },

    getTotals() {
      const state = load();
      const included = state.items.filter(i => i.included);
      const oneTime = included.filter(i => !i.recurring);
      const recurring = included.filter(i => i.recurring);
      return {
        oneTimeLow: oneTime.reduce((s,i) => s + (i.lowPrice || 0), 0),
        oneTimeHigh: oneTime.reduce((s,i) => s + (i.highPrice || 0), 0),
        recurringMo: recurring.reduce((s,i) => s + (i.lowPrice || 0), 0),
        totalHours: included.reduce((s,i) => s + (i.hours || 0), 0),
        count: included.length,
      };
    },

    // Render token string
    fillTokens(tpl) {
      const t = load().tokens;
      return (tpl || '').replace(/\{\{(\w+)\}\}/g, (_, k) => t[k] != null ? t[k] : `{{${k}}}`);
    },

    // Subscribe to changes (returns unsub fn)
    subscribe(fn) {
      const handler = (e) => fn(e.detail || load());
      window.addEventListener('wpsb:cart-changed', handler);
      return () => window.removeEventListener('wpsb:cart-changed', handler);
    },
  };

  window.ProposalCart = ProposalCart;
})();

/* React hook for components */
(function() {
  if (!window.React) return; // Will retry when React loads
  const { useState, useEffect } = window.React;

  window.useProposalCart = function useProposalCart() {
    const [state, setState] = useState(() => window.ProposalCart.get());
    useEffect(() => {
      return window.ProposalCart.subscribe(setState);
    }, []);
    return state;
  };
})();
