// app-store.jsx — global state store + hash router for the working app.
// All mutations go through `useStore()`; state persists to localStorage.

const PCA = window.PCA;
const STORE_KEY = 'pcclaims.v1';

// ── Initial state ─────────────────────────────────────────
function initialState() {
  return {
    mode: 'integrated',                // 'integrated' | 'standalone'
    claims: PCA.seedClaims.map(c => ({ ...c })),  // deep enough; we mutate at claim level only
    notifications: [
      // seed: a couple of historical notifications so the drawer isn't empty
      {
        id: 'N-001',
        claimId: 'CLM-2026-0142',
        type: 'PREAUTH_SUBMITTED',
        channel: 'WHATSAPP',
        phone: '+91 98450 22417',
        body: PCA.notifTemplates.PREAUTH_SUBMITTED({ tpa:'Star Health', hospital: PCA.tenant.name }),
        sentAt: Date.now() - 47 * 60 * 1000,
        status: 'SENT',
      },
      {
        id: 'N-002',
        claimId: 'CLM-2026-0139',
        type: 'PREAUTH_PARTIAL',
        channel: 'WHATSAPP',
        phone: '+91 95381 99221',
        body: PCA.notifTemplates.PREAUTH_PARTIAL({ approved:78000, gap:17000 }),
        sentAt: Date.now() - 22 * 3600 * 1000,
        status: 'SENT',
      },
      {
        id: 'N-003',
        claimId: 'CLM-2026-0136',
        type: 'QUERY_RAISED',
        channel: 'WHATSAPP',
        phone: '+91 98860 71129',
        body: PCA.notifTemplates.QUERY_RAISED(),
        sentAt: Date.now() - 13 * 3600 * 1000,
        status: 'SENT',
      },
    ],
    tariffSchedules: [
      // one seeded — Star Health
      {
        id: 'tariff-star',
        insurerId: 'star-health',
        effectiveFrom: PCA.sampleTariff.effectiveFrom,
        fileName: PCA.sampleTariff.fileName,
        rows: PCA.sampleTariff.rows,
        uploadedAt: Date.now() - 30 * 24 * 3600 * 1000,
      }
    ],
    // ephemeral UI state
    notifDrawerOpen: false,
    toast: null,
  };
}

// ── Persistence ───────────────────────────────────────────
function loadPersisted() {
  try {
    const raw = localStorage.getItem(STORE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    if (parsed && parsed.version === 1) return parsed.state;
  } catch (e) { console.warn('[store] failed to load', e); }
  return null;
}

function persist(state) {
  try {
    // strip ephemeral keys
    const { toast, notifDrawerOpen, ...rest } = state;
    localStorage.setItem(STORE_KEY, JSON.stringify({ version: 1, state: rest }));
  } catch (e) { console.warn('[store] failed to persist', e); }
}

// ── Store context ─────────────────────────────────────────
const StoreCtx = React.createContext(null);

function StoreProvider({ children }) {
  const [state, setStateRaw] = React.useState(() => {
    const persisted = loadPersisted();
    if (persisted) return { ...initialState(), ...persisted, toast:null, notifDrawerOpen:false };
    return initialState();
  });

  // Wrapped setter that persists after every change
  const setState = React.useCallback((updater) => {
    setStateRaw(prev => {
      const next = typeof updater === 'function' ? updater(prev) : updater;
      persist(next);
      return next;
    });
  }, []);

  // ── Action helpers exposed to components ─────────────────
  const api = React.useMemo(() => ({
    state,

    setMode(mode) { setState(s => ({ ...s, mode })); },

    // ── Claims ────────────────────────────────────────────
    findClaim(id) { return state.claims.find(c => c.id === id); },

    updateClaim(id, patch) {
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === id ? (typeof patch === 'function' ? patch(c) : { ...c, ...patch }) : c),
      }));
    },

    createClaim(claimDraft) {
      const id = 'CLM-2026-' + String(150 + Math.floor(Math.random() * 50)).padStart(4, '0');
      const newClaim = {
        id,
        ...claimDraft,
        status: 'INTAKE',
        documents: claimDraft.documents || [],
        charges: [],
        queries: [],
        flags: [],
        coordinator: 'Priya M.',
      };
      setState(s => ({ ...s, claims: [newClaim, ...s.claims] }));
      return id;
    },

    addDocument(claimId, docType) {
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, documents: c.documents.includes(docType) ? c.documents : [...c.documents, docType],
        } : c),
      }));
    },

    removeDocument(claimId, docType) {
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, documents: c.documents.filter(d => d !== docType),
        } : c),
      }));
    },

    addCharge(claimId, charge) {
      const newCharge = { id: 'C' + Math.random().toString(36).slice(2,7), ...charge };
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, charges: [...(c.charges||[]), newCharge],
        } : c),
      }));
    },

    attachImplantBarcode(claimId, chargeId, barcode) {
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, charges: c.charges.map(ch => ch.id === chargeId
            ? { ...ch, implantMissing: false, implantBarcode: barcode } : ch),
        } : c),
      }));
    },

    addQuery(claimId, query) {
      const newQ = { id: 'Q' + Math.random().toString(36).slice(2,5), uploaded: [], status: 'OPEN', raisedAt: Date.now(), ...query };
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, queries: [...(c.queries||[]), newQ],
          status: c.status === 'PREAUTH_SUBMITTED' ? 'PREAUTH_QUERY' : c.status,
        } : c),
      }));
    },

    updateQuery(claimId, queryId, patch) {
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? {
          ...c, queries: c.queries.map(q => q.id === queryId ? { ...q, ...patch } : q),
        } : c),
      }));
    },

    // ── Status transitions (also fire notifications) ─────
    transitionStatus(claimId, newStatus, extra = {}) {
      const claim = state.claims.find(c => c.id === claimId);
      if (!claim) return;
      setState(s => ({
        ...s,
        claims: s.claims.map(c => c.id === claimId ? { ...c, status: newStatus, ...extra } : c),
      }));
      // Fire patient notification if mapped
      api.fireNotificationForStatus(claim, newStatus, extra);
    },

    fireNotificationForStatus(claim, newStatus, extra) {
      const tpl = PCA.notifTemplates;
      const insurer = PCA.findInsurer(claim.insurer)?.name || 'your insurer';
      let body = null;
      let type = newStatus;
      switch (newStatus) {
        case 'PREAUTH_SUBMITTED': body = tpl.PREAUTH_SUBMITTED({ tpa: insurer, hospital: PCA.tenant.name }); break;
        case 'PREAUTH_APPROVED':  body = tpl.PREAUTH_APPROVED({ amount: extra.approvedAmount || claim.approvedAmount || claim.estimatedCost, hospital: PCA.tenant.name }); break;
        case 'PREAUTH_PARTIAL':   body = tpl.PREAUTH_PARTIAL({ approved: extra.approvedAmount, gap: claim.estimatedCost - extra.approvedAmount }); break;
        case 'PREAUTH_DENIED':    body = tpl.PREAUTH_DENIED({ hospital: PCA.tenant.name }); break;
        case 'PREAUTH_QUERY':     body = tpl.QUERY_RAISED(); type = 'QUERY_RAISED'; break;
        default: return;
      }
      if (body) api.addNotification(claim.id, type, claim.patient.phone, body);
    },

    addNotification(claimId, type, phone, body, channel = 'WHATSAPP') {
      const notif = {
        id: 'N-' + Math.random().toString(36).slice(2,7),
        claimId, type, channel, phone, body,
        sentAt: Date.now(),
        status: 'SENT',
      };
      setState(s => ({ ...s, notifications: [notif, ...s.notifications] }));
      api.toast({ icon: 'whatsapp', title: 'WhatsApp sent', body: body.slice(0, 80) + (body.length > 80 ? '…' : '') });
    },

    // ── Ephemeral / UI ────────────────────────────────────
    toggleNotifDrawer() { setStateRaw(s => ({ ...s, notifDrawerOpen: !s.notifDrawerOpen })); },
    closeNotifDrawer()  { setStateRaw(s => ({ ...s, notifDrawerOpen: false })); },

    toast(t) {
      setStateRaw(s => ({ ...s, toast: { id: Math.random(), ...t } }));
      setTimeout(() => setStateRaw(s => s.toast && s.toast.id === t.id ? { ...s, toast: null } : s), 3500);
    },
    clearToast() { setStateRaw(s => ({ ...s, toast: null })); },

    reset() {
      localStorage.removeItem(STORE_KEY);
      setStateRaw(initialState());
    },

    // ── Tariff schedules ─────────────────────────────────
    addTariff(insurerId, fileName) {
      const newTariff = {
        id: 'tariff-' + Math.random().toString(36).slice(2,7),
        insurerId, fileName,
        effectiveFrom: new Date().toISOString().slice(0,10),
        rows: PCA.sampleTariff.rows.slice(0, 6),  // mock parsed rows
        uploadedAt: Date.now(),
      };
      setState(s => ({ ...s, tariffSchedules: [...s.tariffSchedules, newTariff] }));
      return newTariff;
    },

    tariffFor(insurerId) {
      return state.tariffSchedules.find(t => t.insurerId === insurerId);
    },
  }), [state, setState]);

  // Actions the guided tour can trigger directly, so every step does something on tap.
  React.useEffect(() => {
    window.__pcStore = api;
    window.PC_DEMO_ACTIONS = {
      toggleMode() { api.setMode(api.state.mode === 'integrated' ? 'standalone' : 'integrated'); },
    };
  }, [api]);

  return <StoreCtx.Provider value={api}>{children}</StoreCtx.Provider>;
}

function useStore() {
  const ctx = React.useContext(StoreCtx);
  if (!ctx) throw new Error('useStore must be inside <StoreProvider>');
  return ctx;
}

// ── Hash router ───────────────────────────────────────────
// Routes: #/  #/claims  #/claims/new  #/claims/:id  #/claims/:id/:tab
//         #/cfo  #/frontdesk/admit/:id  #/settings/insurers  #/settings/tariffs

function parseRoute(hash) {
  const path = (hash || '#/').replace(/^#/, '');
  const parts = path.split('/').filter(Boolean);
  if (parts.length === 0) return { name: 'dashboard' };
  if (parts[0] === 'claims') {
    if (parts[1] === 'new') return { name: 'claim-new' };
    if (parts[1]) return { name: 'claim', id: parts[1], tab: parts[2] || 'overview' };
    return { name: 'claims' };
  }
  if (parts[0] === 'cfo') return { name: 'cfo' };
  if (parts[0] === 'frontdesk' && parts[1] === 'admit') return { name: 'frontdesk-admit', id: parts[2] };
  if (parts[0] === 'settings') return { name: 'settings', tab: parts[1] || 'insurers' };
  if (parts[0] === 'notifications') return { name: 'notifications' };
  return { name: 'dashboard' };
}

function useRoute() {
  const [hash, setHash] = React.useState(typeof window !== 'undefined' ? window.location.hash : '#/');
  React.useEffect(() => {
    const onHash = () => setHash(window.location.hash || '#/');
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return parseRoute(hash);
}

function navigate(path) {
  window.location.hash = path;
}

Object.assign(window, { StoreProvider, useStore, useRoute, parseRoute, navigate });
