// Intelligence layer — derived signals, confidence sentence, readiness score.
// All read-only views of the store. Pure functions wrapped in hooks so consumers
// re-render when the underlying state changes.

// ─── computation ────────────────────────────────────────────

function computeSignals(state) {
  const out = [];

  // Guest stats from store.
  const guests = state.guests || [];
  const sum = (pred) => guests.filter(pred).reduce((n, g) => n + (g.partySize || 1), 0);
  const attendingN = sum(g => g.status === 'attending');
  const pendingN   = sum(g => g.status === 'pending');
  const dietaryN   = guests.filter(g => g.dietary).length;

  // 1. Vendor final payments
  (state.vendors || []).forEach(v => {
    const due = (v.total || 0) - (v.paid || 0);
    if (!v.next) return;
    const lower = v.next.toLowerCase();
    if (lower.includes('final') || (lower.includes('due') && due > 0) || v.status === 'due') {
      out.push({
        id: `pay-${v.id || v.name}`,
        severity: 'urgent',
        kind: 'payment',
        title: `Final payment to ${v.name}`,
        detail: v.next,
        amount: due > 0 ? due : null,
        cta: 'vendors',
      });
    }
  });

  // 2. Categories over plan
  (state.budgetCategories || []).forEach(c => {
    if (c.planned > 0 && c.spent > c.planned) {
      out.push({
        id: `over-${c.id || c.name}`,
        severity: 'warning',
        kind: 'budget',
        title: `${c.name} is over plan`,
        detail: `Spent ${fmt$(c.spent)} of ${fmt$(c.planned)}`,
        amount: c.spent - c.planned,
        cta: 'budget',
      });
    }
  });

  // 3. RSVPs pending
  if (pendingN >= 10) {
    out.push({
      id: 'rsvp-pending',
      severity: 'warning',
      kind: 'rsvp',
      title: `${pendingN} guests haven't responded`,
      detail: 'Send a friendly follow-up note',
      count: pendingN,
      cta: 'guests',
    });
  } else if (pendingN > 0) {
    out.push({
      id: 'rsvp-pending',
      severity: 'info',
      kind: 'rsvp',
      title: `${pendingN} ${pendingN === 1 ? 'guest hasn\'t' : 'guests haven\'t'} responded`,
      detail: 'A nudge would help',
      count: pendingN,
      cta: 'guests',
    });
  }

  // 4. Dietary alerts
  if (dietaryN > 0) {
    out.push({
      id: 'diet',
      severity: 'info',
      kind: 'rsvp',
      title: `${dietaryN} ${dietaryN === 1 ? 'dietary note' : 'dietary notes'} to track`,
      detail: 'Confirm with your caterer',
      cta: 'guests',
    });
  }

  // 5. Seating gaps — derived from attending headcount minus filled seats.
  const filledSeats = (state.tables || []).reduce(
    (n, t) => n + (t.seats || []).filter(Boolean).length, 0
  );
  const seatingUnassigned = Math.max(0, attendingN - filledSeats);
  if (seatingUnassigned > 0) {
    out.push({
      id: 'seat',
      severity: 'info',
      kind: 'seating',
      title: `${seatingUnassigned} ${seatingUnassigned === 1 ? 'guest' : 'guests'} not yet seated`,
      detail: 'Place remaining guests at tables',
      count: seatingUnassigned,
      cta: 'seating',
    });
  }

  // 6. Next calendar event — from store.
  const nextEvent = (state.events || [])
    .filter(e => e.dateISO && new Date(e.dateISO) >= new Date())
    .sort((a, b) => a.dateISO < b.dateISO ? -1 : 1)[0];
  if (nextEvent) {
    const d = new Date(nextEvent.dateISO);
    const dayLabel = d.toLocaleDateString('en-US', { weekday: 'short' });
    const dateLabel = d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
    out.push({
      id: `cal-${nextEvent.id}`,
      severity: 'info',
      kind: 'event',
      title: nextEvent.title || 'Untitled event',
      detail: `${dayLabel} · ${dateLabel}${nextEvent.time ? ' · ' + nextEvent.time : ''}`,
      cta: 'cal',
    });
  }

  const order = { urgent: 0, warning: 1, info: 2 };
  out.sort((a, b) => order[a.severity] - order[b.severity]);
  return out;
}

function computeConfidence(state, signals) {
  const urgent = signals.filter(s => s.severity === 'urgent');
  const warning = signals.filter(s => s.severity === 'warning');

  const guests = state.guests || [];
  const pendingN = guests.filter(g => g.status === 'pending').reduce((n, g) => n + (g.partySize || 1), 0);

  // Positive — what's going well
  const vendorList = state.vendors || [];
  const vendorBooked = vendorList.filter(v => v.status !== 'researching').length;
  const vendorTotalCount = vendorList.length;
  const vendorRatio = vendorTotalCount ? vendorBooked / vendorTotalCount : 0;
  const totalBudget = state.wedding.budget || 0;
  const totalSpent = (state.budgetCategories || [])
    .reduce((n, c) => n + (c.spent || 0), 0);
  const budgetRatio = totalBudget ? totalSpent / totalBudget : 0;
  let positive;
  if (vendorRatio >= 0.75)        positive = "You're ahead on vendors";
  else if (budgetRatio < 0.75)    positive = "Your budget is in good shape";
  else if (state.wedding && state.tasks.some(t => t.status === 'done'))
                                  positive = "You're making steady progress";
  else                            positive = "You're on track";

  // Concern — pick the single most pressing thing
  let concern;
  if (urgent.length === 1)        concern = urgent[0].title.toLowerCase();
  else if (urgent.length > 1)     concern = `${urgent.length} payments need attention this week`;
  else if (warning.length) {
    const w = warning[0];
    if (w.kind === 'rsvp')        concern = `${pendingN} RSVPs need a nudge`;
    else if (w.kind === 'budget') concern = `${w.title.toLowerCase()}`;
    else                          concern = `${w.title.toLowerCase()}`;
  }

  return concern
    ? `${positive}, but ${concern} this week.`
    : `${positive}. Nothing urgent today.`;
}

function computeReadiness(state) {
  const guests = state.guests || [];
  const sum = (pred) => guests.filter(pred).reduce((n, g) => n + (g.partySize || 1), 0);
  const attending = sum(g => g.status === 'attending');
  const total     = sum(() => true);
  const responded = sum(g => g.status !== 'pending');

  const totalBudget = state.wedding.budget || 0;
  const totalSpent  = (state.budgetCategories || []).reduce((n, c) => n + (c.spent || 0), 0);

  const breakdown = {
    Vendors:  (() => {
      const vs = state.vendors || [];
      if (!vs.length) return 0;
      return clamp(vs.filter(v => v.status !== 'researching').length / vs.length);
    })(),
    Guests:   total > 0 ? clamp(responded / total) : 0,
    Budget:   totalBudget > 0
                ? clamp(1 - Math.max(0, (totalSpent - totalBudget) / totalBudget)) * 0.6
                  + clamp(totalSpent / totalBudget) * 0.4
                : 0,
    Seating:  (() => {
      if (attending <= 0) return 0;
      const filled = (state.tables || []).reduce(
        (n, t) => n + (t.seats || []).filter(Boolean).length, 0
      );
      return clamp(filled / attending);
    })(),
    Timeline: state.tasks.length
                ? clamp(state.tasks.filter(t => t.status === 'done').length / state.tasks.length)
                : 0.5,
  };
  const score = Object.values(breakdown).reduce((a, b) => a + b, 0) / Object.keys(breakdown).length;
  return { score: Math.round(score * 100), breakdown };
}

function clamp(n) { return Math.max(0, Math.min(1, n)); }

// ─── hooks ──────────────────────────────────────────────────

function usePlanningSignals() {
  const { state } = useStore();
  return React.useMemo(() => computeSignals(state), [state]);
}

function usePlanningConfidence() {
  const { state } = useStore();
  const signals = usePlanningSignals();
  return React.useMemo(() => computeConfidence(state, signals), [state, signals]);
}

function useReadinessScore() {
  const { state } = useStore();
  return React.useMemo(() => computeReadiness(state), [state]);
}

// ─── SignalCard — replaces TaskCard in the triage list ──────

function SignalCard({ signal, onClick, compact = false }) {
  const sevMeta = {
    urgent:  { tone: 'amber',   dot: W.red },
    warning: { tone: 'clay',    dot: W.clay },
    info:    { tone: 'sage',    dot: W.sage },
  };
  const kindIcon = {
    payment: 'wallet', rsvp: 'users', budget: 'wallet',
    seating: 'rings',  event: 'calendar',
  };
  const s = sevMeta[signal.severity] || sevMeta.info;
  const labelMap = {
    urgent: 'This week', warning: 'Watch', info: 'Heads up',
  };

  return (
    <Card onClick={onClick} style={{
      padding: compact ? 12 : 14,
      display: 'flex', alignItems: 'center', gap: 14,
      cursor: onClick ? 'pointer' : 'default',
    }}>
      {/* severity dot */}
      <div style={{
        width: 40, height: 40, borderRadius: 999,
        background: '#fbf6ea', border: `0.5px solid ${W.lineSoft}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0, position: 'relative',
      }}>
        <Icon name={kindIcon[signal.kind] || 'sparkle'} size={17} color={W.clayDeep} strokeWidth={1.4}/>
        <div style={{
          position: 'absolute', top: -2, right: -2,
          width: 9, height: 9, borderRadius: 999, background: s.dot,
          border: `1.5px solid ${W.card}`,
        }}/>
      </div>

      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 3 }}>
          <Pill tone={s.tone} style={{ padding: '3px 7px', fontSize: 9.5 }}>
            {labelMap[signal.severity]}
          </Pill>
          {signal.detail && (
            <span style={{
              fontFamily: FONT_UI, fontSize: 11.5, color: W.muted,
              whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
              maxWidth: 180,
            }}>{signal.detail}</span>
          )}
        </div>
        <div style={{
          fontFamily: FONT_UI, fontSize: 14.5, fontWeight: 500,
          color: W.ink, lineHeight: 1.25,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{signal.title}</div>
      </div>

      {signal.amount ? (
        <div style={{
          fontFamily: FONT_DISPLAY, fontSize: 18, color: W.ink, letterSpacing: -0.2,
        }}>{fmt$(signal.amount)}</div>
      ) : signal.count ? (
        <div style={{
          fontFamily: FONT_DISPLAY, fontSize: 20, color: W.ink, letterSpacing: -0.3,
        }}>{signal.count}</div>
      ) : (
        <Icon name="chevron" size={14} color={W.faint}/>
      )}
    </Card>
  );
}

// ─── ReadinessRing — single number + tiny breakdown ────────

function ReadinessRing({ size = 96 }) {
  const { score, breakdown } = useReadinessScore();
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 16,
    }}>
      <ProgressRing value={score / 100} size={size} stroke={6} color={W.clay}>
        <div style={{ textAlign: 'center' }}>
          <div style={{
            fontFamily: FONT_DISPLAY, fontSize: size * 0.32, color: W.ink,
            letterSpacing: -0.5, lineHeight: 1,
          }}>{score}</div>
          <div style={{
            fontFamily: FONT_UI, fontSize: 8.5, fontWeight: 600,
            letterSpacing: 1.4, color: W.muted, textTransform: 'uppercase', marginTop: 2,
          }}>Ready</div>
        </div>
      </ProgressRing>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6 }}>
        {Object.entries(breakdown).map(([k, v]) => (
          <div key={k} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <div style={{
              width: 70,
              fontFamily: FONT_UI, fontSize: 11, color: W.ink2,
            }}>{k}</div>
            <div style={{ flex: 1 }}>
              <Bar value={v} color={W.clay} height={3}/>
            </div>
            <div style={{
              width: 30, textAlign: 'right',
              fontFamily: FONT_MONO, fontSize: 10.5, color: W.muted,
            }}>{Math.round(v * 100)}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, {
  usePlanningSignals, usePlanningConfidence, useReadinessScore,
  SignalCard, ReadinessRing,
});
