// TriageDeck.jsx — Card-based decision-tree triage (DecisionTreeEngine). On completion
// writes audit state and routes to snapshot, emergency, folio, or Smile Audit.
const { useState: useTDs, useEffect: useTDe, useRef: useTDr } = React;

const SNAPSHOT_FETCH_MS = 20000;

async function fetchJson(url, opts, timeoutMs = SNAPSHOT_FETCH_MS) {
  const ac = new AbortController();
  const timer = setTimeout(() => ac.abort(), timeoutMs);
  try {
    const resp = await fetch(url, { ...opts, signal: ac.signal });
    if (!resp.ok) return null;
    return await resp.json();
  } catch (_) {
    return null;
  } finally {
    clearTimeout(timer);
  }
}

function TriageDeck({ go, state, set, mode = 'patient', lang, setLang }) {
  const [current, setCurrent] = useTDs(null);
  const [history, setHistory] = useTDs([]);
  const [value, setValue] = useTDs(null);
  const [loading, setLoading] = useTDs(false);
  const [summarizing, setSummarizing] = useTDs(false);
  const [summarizeError, setSummarizeError] = useTDs(null);
  const [progress, setProgress] = useTDs(0);
  const [emergencyOpen, setEmergencyOpen] = useTDs(false);
  const [pendingContinue, setPendingContinue] = useTDs(null);
  const snapshotRunRef = useTDr(false);

  const gateCheck = (nextHistory, capturedValue, direction) => {
    const guard = window.EmergencyGuard;
    if (!guard || !guard.shouldGate) return { gate: false };
    const painLevel = current?.id === 'pain_level' && typeof capturedValue === 'number'
      ? capturedValue
      : guard.painFromHistory(nextHistory);
    const freeText = nextHistory
      .map((h) => (typeof h.answer === 'string' ? h.answer : ''))
      .filter(Boolean)
      .join(' ');
    return guard.shouldGate({
      history: nextHistory,
      painLevel,
      text: freeText,
      symptoms: deriveSymptoms(window.DecisionTreeEngine.complete(mode, nextHistory), nextHistory),
    });
  };

  const applyFinalState = (final, nextHistory) => {
    set && set((s) => ({
      ...s,
      swipe: final,
      teeth: final.teeth,
      toothPain: final.toothPain,
      symptoms: deriveSymptoms(final, nextHistory),
      severity: final.pain.level,
      interests: final.interests,
      urgency_flagged: final.urgency_hint === 'emergency' || final.pain.level >= 8,
      insurance: final.hasInsurance === true
        ? (s.insurance && s.insurance !== 'No insurance' ? s.insurance : 'Other / not sure')
        : 'No insurance',
    }));
    if (window.VonAttribution) {
      window.VonAttribution.onAuditComplete({
        source: 'triage_deck',
        mode,
        urgency: final.urgency_hint,
        severity: final.pain?.level,
      });
    }
  };

  const runSnapshotAndGo = async (nextHistory) => {
    if (snapshotRunRef.current) return;
    snapshotRunRef.current = true;
    setSummarizing(true);
    setSummarizeError(null);
    setLoading(true);

    const final = window.DecisionTreeEngine.complete(mode, nextHistory);
    const symptoms = deriveSymptoms(final, nextHistory);
    const freeText = nextHistory
      .map((h) => (typeof h.answer === 'string' ? h.answer : ''))
      .filter(Boolean)
      .join(' ');
    const triageText = [symptoms.join(', '), freeText].filter(Boolean).join('; ');
    const payload = {
      symptoms,
      severity: final.pain?.level ?? 0,
      teeth: final.teeth || [],
      zip: (state && state.zip) || '',
      insurance: final.hasInsurance === true
        ? ((state && state.insurance) || 'Other / not sure')
        : 'No insurance',
      pain: final.pain,
      interests: final.interests || [],
    };

    try {
      const triage = await fetchJson('/api/triage', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ symptoms: triageText || symptoms, severity: payload.severity }),
      });
      if (triage && triage.gateEmergencyContent) {
        applyFinalState(final, nextHistory);
        set && set((s) => ({ ...s, _triage: triage }));
        go('emergency');
        return;
      }

      const snap = await fetchJson('/api/snapshot', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(payload),
      });
      if (!snap || !snap.ok) {
        throw new Error('snapshot_unavailable');
      }

      const langPref = (state && state.language) || 'English';
      const dir = await fetchJson(
        `/api/directory?zip=${encodeURIComponent(payload.zip)}&insurance=${encodeURIComponent(payload.insurance)}&language=${encodeURIComponent(langPref)}&limit=3`,
        { method: 'GET' },
      ) || { results: [] };

      applyFinalState(final, nextHistory);
      set && set((s) => ({ ...s, _snapshot: snap, _directory: dir, _triage: triage || s._triage }));
      go('snapshot');
    } catch (_) {
      snapshotRunRef.current = false;
      setSummarizeError("Couldn't build your snapshot. Check your connection and try again.");
    } finally {
      setSummarizing(false);
      setLoading(false);
    }
  };

  const finishDeck = async (nextHistory) => {
    const final = window.DecisionTreeEngine.complete(mode, nextHistory);
    applyFinalState(final, nextHistory);
    if (mode === 'clinician') go('folio');
    else if (final.urgency_hint === 'emergency') go('emergency');
    else if (final.teeth && final.teeth.length === 0) go('audit-1');
    else await runSnapshotAndGo(nextHistory);
  };

  useTDe(() => {
    if (current?.kind === 'severity' && typeof value !== 'number') {
      setValue(current.min ?? 0);
    }
  }, [current?.id]);

  useTDe(() => {
    let alive = true;
    (async () => {
      if (window.DecisionTreeEngine?.loadRemoteTrees) {
        await window.DecisionTreeEngine.loadRemoteTrees({
          mode,
          surface: mode === 'clinician' ? 'platform' : 'triage',
        });
      }
      const card = await window.DecisionTreeEngine.next({ mode });
      if (alive) setCurrent(card);
    })();
    return () => { alive = false; };
  }, [mode]);

  const persistProgress = (nextHistory) => {
    set && set((s) => ({ ...s, swipe: window.DecisionTreeEngine.complete(mode, nextHistory) }));
  };

  const onAnswer = async (direction, capturedValue) => {
    if (!current) return;
    if (current.id === 'ai_summary' && mode === 'patient') return;

    let answer;
    if (current.kind === 'yesno') answer = direction;
    else if (direction === 'no' || direction === 'skip') answer = null;
    else if (direction === 'maybe') answer = capturedValue ?? null;
    else answer = capturedValue ?? null;

    const nextHistory = [...history, { id: current.id, answer, direction }];
    const gate = gateCheck(nextHistory, capturedValue, direction);

    const proceed = async () => {
      setHistory(nextHistory);
      setProgress((p) => p + 1);
      setValue(null);
      setLoading(true);
      persistProgress(nextHistory);

      const nextCard = await window.DecisionTreeEngine.next({
        mode,
        currentId: current.id,
        lastAnswer: direction,
        state: { ...(state || {}), history: nextHistory },
      });
      setLoading(false);

      if (!nextCard) {
        await finishDeck(nextHistory);
        return;
      }
      if (nextCard.id === 'ai_summary' && mode === 'patient') {
        setCurrent(nextCard);
        await runSnapshotAndGo(nextHistory);
        return;
      }
      if (nextCard.ai) {
        const finalGate = window.EmergencyGuard?.shouldGate({
          history: nextHistory,
          painLevel: window.EmergencyGuard.painFromHistory(nextHistory),
          urgency_hint: window.DecisionTreeEngine.complete(mode, nextHistory).urgency_hint,
        });
        if (finalGate?.gate) {
          set && set((s) => ({ ...s, urgency_flagged: true }));
          setPendingContinue(() => () => finishDeck(nextHistory));
          setEmergencyOpen(true);
          return;
        }
      }
      setCurrent(nextCard);
    };

    if (gate?.gate) {
      set && set((s) => ({ ...s, urgency_flagged: true }));
      setPendingContinue(() => proceed);
      setEmergencyOpen(true);
      return;
    }
    await proceed();
  };

  const dismissEmergency = () => {
    setEmergencyOpen(false);
    const cont = pendingContinue;
    setPendingContinue(null);
    if (cont) cont();
  };

  const onBack = async () => {
    if (history.length === 0 || loading || summarizing) return;
    snapshotRunRef.current = false;
    setSummarizeError(null);
    const nextHistory = history.slice(0, -1);
    setHistory(nextHistory);
    setProgress((p) => Math.max(0, p - 1));
    persistProgress(nextHistory);
    setLoading(true);
    let card = await window.DecisionTreeEngine.next({ mode });
    for (const entry of nextHistory) {
      card = await window.DecisionTreeEngine.next({
        mode,
        currentId: entry.id,
        lastAnswer: entry.direction,
        state: { ...(state || {}), history: nextHistory },
      });
    }
    setLoading(false);
    setCurrent(card);
    const last = nextHistory[nextHistory.length - 1];
    setValue(last ? last.answer : null);
  };

  if (!current) {
    return (
      <div className="app has-bottom-nav-target">
        <Masthead lang={lang} setLang={setLang} go={go} />
        <main>
          <div className="container" style={{ padding: 'var(--s-8) 0', maxWidth: 520 }}>
            {window.Skeleton
              ? <Skeleton lines={4} height={16} />
              : <p className="t-meta">Loading…</p>}
          </div>
        </main>
        <Footer go={go} />
      </div>
    );
  }

  const eyebrow = mode === 'clinician' ? 'Clinician triage' : 'Patient triage';
  const onSummarizeScreen = current.id === 'ai_summary' && mode === 'patient';

  return (
    <div className="app has-bottom-nav-target">
      <Masthead lang={lang} setLang={setLang} go={go} />
      <main>
        <div className="container" style={{ maxWidth: 520, padding: 'var(--s-6) 0' }}>
          <div
            className="banner info"
            role="note"
            style={{ marginBottom: 'var(--s-3)' }}
          >
            AI information only, not a diagnosis — confirm with a licensed dentist.
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 'var(--s-3)' }}>
            <div className="t-eyebrow">{eyebrow}</div>
            <div style={{ display: 'flex', gap: 4 }} aria-hidden="true">
              {Array.from({ length: Math.max(progress + 1, 6) }, (_, i) => (
                <span
                  key={i}
                  className={`triage-progress-dot${i < progress ? ' is-on' : ''}`}
                />
              ))}
            </div>
          </div>
          {onSummarizeScreen ? (
            <article
              className="triage-card triage-card--patient"
              aria-live="polite"
              style={{ alignItems: 'center', justifyContent: 'center', textAlign: 'center' }}
            >
              <div className="t-eyebrow">Quick triage</div>
              <h2 className="triage-card-title">
                {summarizeError ? 'Snapshot paused' : 'Summarizing…'}
              </h2>
              <p style={{ margin: 0, color: 'var(--mut)', fontSize: 14, maxWidth: 360 }}>
                {summarizeError
                  ? summarizeError
                  : 'Crafting your personalized Smile Snapshot from what you shared.'}
              </p>
              {summarizeError ? (
                window.ErrorRetry
                  ? <ErrorRetry
                      message={summarizeError}
                      onRetry={() => {
                        snapshotRunRef.current = false;
                        runSnapshotAndGo(history);
                      }}
                    />
                  : (
                    <button
                      type="button"
                      className="btn btn-primary td-cta"
                      onClick={() => {
                        snapshotRunRef.current = false;
                        runSnapshotAndGo(history);
                      }}
                    >
                      Try again
                    </button>
                  )
              ) : (
                <div style={{ width: '100%', maxWidth: 280 }} aria-busy="true">
                  {window.Skeleton && <Skeleton lines={3} height={12} />}
                  <p style={{ margin: '8px 0 0', color: 'var(--mut)', fontSize: 13 }}>
                    {summarizing || loading ? 'Generating snapshot…' : 'Starting…'}
                  </p>
                </div>
              )}
            </article>
          ) : (
            <TriageCard
              card={current}
              value={value}
              onChange={setValue}
              onAnswer={onAnswer}
              onBack={onBack}
              canBack={history.length > 0 && !summarizing}
              mode={mode}
            />
          )}
          {loading && !onSummarizeScreen && (
            <p style={{ textAlign: 'center', color: 'var(--mut)', marginTop: 8, fontSize: 12 }} aria-live="polite">
              Loading next step…
            </p>
          )}
          {window.EmergencyOverlay && (
            <window.EmergencyOverlay open={emergencyOpen} onDismiss={dismissEmergency} go={go} />
          )}
          {window.TreeVoteBar && (
            <TreeVoteBar mode={mode} compact />
          )}
          {!onSummarizeScreen && (
            <div style={{ textAlign: 'center', marginTop: 'var(--s-4)' }}>
              <button
                type="button"
                className="bc-link"
                style={{ background: 'none', border: 0, cursor: 'pointer', color: 'var(--ink-3)', fontSize: 12 }}
                onClick={() => go('audit-1')}
              >
                Skip triage — open the full Smile Audit →
              </button>
            </div>
          )}
        </div>
      </main>
      <Footer go={go} />
    </div>
  );
}

function deriveSymptoms(final, history) {
  const out = [];
  if (final.pain.level >= 1) out.push('tooth pain');
  if (final.pain.type === 'sharp') out.push('sharp pain');
  if (final.pain.type === 'throbbing') out.push('throbbing');
  if (final.pain.type === 'sensitivity') out.push('sensitivity to cold');
  if (final.pain.triggers.includes('cold')) out.push('sensitivity to cold');
  if (final.pain.triggers.includes('hot')) out.push('sensitivity to hot');
  if (final.pain.triggers.includes('chewing')) out.push('pain when chewing');
  if (final.urgency_hint === 'emergency') out.push('swelling');
  if (Array.isArray(history)) {
    const concern = history.find((h) => h.id === 'concern_today');
    if (concern && concern.answer) {
      const map = {
        checkup: 'Want a checkup',
        cleaning: 'Overdue for cleaning',
        cosmetic: 'Cosmetic — whiten',
        'second-opinion': 'Second opinion',
        kids: "Kid's tooth concern",
      };
      const label = map[concern.answer];
      if (label) out.push(label);
    }
  }
  return [...new Set(out)];
}

window.TriageDeck = TriageDeck;
