/* ============================================================
   MUIY — General Timeline for Clinical & Laboratory Evaluation
   Redesigned: a mobile-first, expandable monitoring roadmap.
   · Overview summary (completed / due soon / overdue)
   · Search + category filter chips
   · Per-category accordions of test cards
   · Each test: cadence visual + last done / next due + status
   Reference schedule = TIF guidelines; real status is pulled from
   the canonical engine (window.MON) wherever a test is tracked.
   Exposes window.MonTimetable.
   ============================================================ */

/* ---- cadence vocabulary -------------------------------------------------- */
const TL_FREQ_TXT = { m1: 'Monthly', m3: 'Every 3 months', m6: 'Every 6 months', m12: 'Annually', m24: 'Every 2 years', aci: 'As needed', init: 'At baseline' };
const TL_FREQ_MO = { m1: 1, m3: 3, m6: 6, m12: 12, m24: 24 };
function tlFreqLabel(f) { return f.map((k) => TL_FREQ_TXT[k] || k).join(' · '); }
function tlPrimaryMonths(f) { for (const k of ['m1', 'm3', 'm6', 'm12', 'm24']) if (f.indexOf(k) !== -1) return TL_FREQ_MO[k]; return null; }

/* ---- schedule data (TIF), grouped to match the filter chips -------------- */
/* row: { name, id?(registry match), f:[cadence keys], startAge?, group?, note? } */
const TL_DATA = [
  { cat: 'Baseline information', chip: 'Baseline', icon: 'clipboard', rows: [
    { name: 'Haemoglobin fraction', f: ['init'] },
    { name: 'DNA mapping (alpha & beta)', f: ['init'] },
    { name: 'Red blood cell phenotype', f: ['init'], note: 'Done once, at baseline.' },
  ] },
  { cat: 'Haematology', chip: 'Haematology', icon: 'drop', rows: [
    { name: 'Complete blood count (CBC)', id: 'haemoglobin', f: ['m3'], note: 'Every 1–2 weeks while taking Deferiprone.' },
    { name: 'Coombs (direct)', f: ['aci'] },
    { name: 'Packed red cells transfused', f: ['m6', 'm12'] },
  ] },
  { cat: 'Iron monitoring', chip: 'Iron', icon: 'sparkle', rows: [
    { name: 'Serum ferritin', id: 'ferritin', f: ['m3'] },
    { name: 'Liver iron concentration (MRI)', f: ['m12', 'aci'], startAge: 8, note: 'From age 8. Histology if hepatitis is present.' },
    { name: 'Audiology evaluation', f: ['m12', 'aci'] },
    { name: 'Ophthalmology evaluation', f: ['m12'] },
    { name: 'Iron & TIBC', f: ['aci'] },
    { name: 'Transferrin saturation', f: ['aci'] },
  ] },
  { cat: 'Liver function & disease', chip: 'Liver', icon: 'clipboard', rows: [
    { name: 'AST, ALT, γGT', id: 'ast', f: ['m3'], note: 'Monthly if on deferasirox.' },
    { name: 'Bilirubin (total)', id: 'bilirubin_total', f: ['m3'] },
    { name: 'Bilirubin (direct)', id: 'bilirubin_direct', f: ['m3'] },
    { name: 'Albumin', id: 'albumin', f: ['m3'] },
    { name: 'Hepatitis A serology', f: ['m12'] },
    { name: 'Hepatitis B serology', f: ['m12'] },
    { name: 'Hepatitis B PCR', f: ['m12', 'aci'], note: 'If serology is positive.' },
    { name: 'Hepatitis C serology', f: ['m12'] },
    { name: 'Hepatitis C PCR', f: ['m12', 'aci'], note: 'If serology is positive.' },
    { name: 'PT, PTT', f: ['aci'], note: 'Before a liver biopsy; more often with active hepatitis.' },
    { name: 'Liver ultrasound', f: ['m12'] },
    { name: 'Fibroscan', f: ['m24', 'aci'] },
    { name: 'Liver biopsy', f: ['aci'] },
  ] },
  { cat: 'Endocrine', chip: 'Endocrine', icon: 'heart', rows: [
    { name: 'T3, free T4, TSH', id: 'tsh', f: ['m12'], startAge: 5, note: 'Start at 5 years.' },
    { name: 'PTH', id: 'pth', f: ['m12'], startAge: 5, note: 'Start at 5 years.' },
    { name: 'Calcium, ionized calcium', id: 'calcium', f: ['m3'], startAge: 5, note: 'Start at 5 years.' },
    { name: 'Fasting glucose', id: 'fasting_blood_sugar', f: ['m3'], startAge: 5, note: 'Start at 5 years.' },
    { name: 'Glucose tolerance test', f: ['m12'], startAge: 10, note: 'Annually after age 10.' },
    { name: 'IGF-1, IGF BP-3', f: ['aci'], note: 'At noted growth delay.' },
    { name: 'LH', id: 'lh', f: ['aci'], note: 'At pubertal delay: 12y girls, 14y boys.' },
    { name: 'FSH', id: 'fsh', f: ['aci'], note: 'At pubertal delay: 12y girls, 14y boys.' },
    { name: 'Estradiol', id: 'estradiol', f: ['aci'], note: 'At pubertal delay (girls).' },
  ] },
  { cat: 'Cardiology', chip: 'Cardiology', icon: 'heart', rows: [
    { name: 'ECG', f: ['m12'] },
    { name: 'ECG Holter', f: ['aci'] },
    { name: 'Exercise ECG (ergometry)', f: ['m12', 'aci'] },
    { name: 'Echocardiography', f: ['m12', 'aci'] },
    { name: 'Cardiac MRI T2*', f: ['m12', 'aci'], startAge: 8, note: 'From age 8 years.' },
  ] },
  { cat: 'Growth & development', chip: 'Growth & Development', icon: 'chart', rows: [
    { name: 'Height', f: ['m3'], group: 'children' },
    { name: 'Sitting height', f: ['m3'], group: 'children' },
    { name: 'Weight', f: ['m3'], group: 'children' },
    { name: 'Growth velocity', f: ['m3'], group: 'children' },
    { name: 'Bone age', f: ['m12'], group: 'children' },
    { name: 'Tanner stage', f: ['m3'], group: 'children', startAge: 10, note: 'After age 10.' },
    { name: 'Height (adults)', f: ['m12'], group: 'adults' },
    { name: 'Weight (adults)', f: ['m3'], group: 'adults' },
  ] },
  { cat: 'Bone health', chip: 'Bone Health', icon: 'shield', rows: [
    { name: 'DEXA scan', f: ['m24'] },
    { name: 'Vitamin D level', id: 'vitamin_d', f: ['m6'] },
  ] },
  { cat: 'Other periodic', chip: 'Other', icon: 'clipboard', rows: [
    { name: 'Urea & creatinine', id: 'urea', f: ['m3'], note: 'Monthly if on deferasirox.' },
    { name: 'Urinalysis', f: ['m6'] },
    { name: 'Zinc level', f: ['m6'] },
    { name: 'Dental review', f: ['m12'] },
  ] },
];

/* filter chips, in display order */
const TL_CHIPS = ['All', 'Baseline', 'Haematology', 'Iron', 'Liver', 'Endocrine', 'Cardiology', 'Growth & Development', 'Bone Health', 'Other'];

/* ---- status palette (4 states + reference) ------------------------------- */
const TL_STATUS = {
  uptodate:  { label: 'Up to date', color: 'var(--success)', wash: 'var(--success-wash)' },
  duesoon:   { label: 'Due soon',   color: 'var(--warning)', wash: 'var(--warning-wash)' },
  overdue:   { label: 'Overdue',    color: 'var(--danger)', wash: 'var(--danger-wash)' },
  never:     { label: 'Never done', color: '#7C7264', wash: '#EEF3F3' },
  reference: { label: 'Reference',  color: '#3E9AA0', wash: 'var(--sky-wash)' },
};

/* is a row relevant to this patient? (age / sex / population) */
function tlApplies(row, profile) {
  if (!profile || profile.age == null) return true;
  const age = profile.age;
  if (row.group === 'children' && age >= 18) return false;
  if (row.group === 'adults' && age < 18) return false;
  if (row.startAge && age < row.startAge) return false;
  if (row.id && window.MON) {
    const t = MON.REGISTRY.find((x) => x.id === row.id);
    if (t && !MON.appliesTo(t, profile)) return false;
  }
  return true;
}

/* compute the live state of a row (real status if tracked, else reference) */
function tlRowState(row, profile, logs) {
  if (row.id && window.MON) {
    const t = MON.REGISTRY.find((x) => x.id === row.id);
    if (t) {
      const st = MON.statusOf(t, profile, logs);
      let key = 'uptodate';
      if (st.never) key = 'never';
      else if (st.status === 'OVERDUE') key = 'overdue';
      else if (st.status === 'DUESOON') key = 'duesoon';
      else if (st.status === 'OPTIONAL') key = 'reference';
      return { tracked: true, key, st };
    }
  }
  return { tracked: false, key: 'reference', st: null };
}

/* ---- compact cadence timeline (dot track) -------------------------------- */
function TlCadence({ f }) {
  const months = tlPrimaryMonths(f);
  const label = tlFreqLabel(f);
  let dots = null;
  if (months) {
    const count = Math.min(Math.floor(24 / months) + 1, 6);
    dots = Array.from({ length: Math.max(count, 2) });
  }
  return (
    <div className="tl-cad">
      <span className="tl-cad-pill">{label}</span>
      {dots && (
        <div className="tl-track" aria-hidden="true">
          <span className="tl-track-line" />
          {dots.map((_, i) => <span key={i} className={'tl-track-dot' + (i === 0 ? ' first' : '')} />)}
        </div>
      )}
    </div>
  );
}

/* ---- a single test card -------------------------------------------------- */
function TlTestRow({ row, profile, logs }) {
  const state = tlRowState(row, profile, logs);
  const meta = TL_STATUS[state.key];
  const st = state.st;
  return (
    <div className="tl-test">
      <div className="tl-test-head">
        <span className="tl-status-dot" style={{ background: meta.color }} />
        <span className="tl-test-name">{row.name}</span>
        <span className="tl-badge" style={{ background: meta.wash, color: meta.color }}>{meta.label}</span>
      </div>
      <TlCadence f={row.f} />
      {state.tracked && st && !st.never && (
        <div className="tl-meta">
          <span className="tl-meta-i"><span className="tl-meta-k">Last done</span><span className="tl-meta-v">{TC.fmtDate(st.last.date, { day: 'numeric', month: 'short', year: 'numeric' })}</span></span>
          <span className="tl-meta-i"><span className="tl-meta-k">Next due</span><span className="tl-meta-v" style={{ color: meta.color }}>{st.nextDue ? TC.fmtDate(st.nextDue, { day: 'numeric', month: 'short', year: 'numeric' }) : '—'}</span></span>
        </div>
      )}
      {state.tracked && st && st.never && (
        <div className="tl-meta"><span className="tl-meta-i"><span className="tl-meta-k">Records</span><span className="tl-meta-v">No result logged yet</span></span></div>
      )}
      {row.note && <div className="tl-note">{row.note}</div>}
    </div>
  );
}

/* ---- one category accordion --------------------------------------------- */
function TlCategory({ group, rows, open, onToggle, profile, logs }) {
  // attention count = overdue + due soon + never (tracked)
  let attn = 0;
  rows.forEach((r) => { const s = tlRowState(r, profile, logs); if (s.tracked && (s.key === 'overdue' || s.key === 'duesoon' || s.key === 'never')) attn++; });
  return (
    <div className={'tl-cat' + (open ? ' open' : '')}>
      <button className="tl-cat-head" onClick={onToggle} aria-expanded={open}>
        <span className="tl-cat-leaf"><Icon name={group.icon} size={16} color="var(--sky-deep)" /></span>
        <span className="tl-cat-tx">
          <span className="tl-cat-name">{group.cat}</span>
          <span className="tl-cat-sub">{rows.length} test{rows.length === 1 ? '' : 's'}</span>
        </span>
        {attn > 0 && <span className="tl-cat-attn">{attn}</span>}
        <Icon name="chevD" size={18} color="var(--ink-3)" style={{ flex: 'none', transition: 'transform .22s', transform: open ? 'rotate(180deg)' : 'none' }} />
      </button>
      <div className={'mon-acc' + (open ? ' open' : '')} aria-hidden={!open}>
        <div>
          {open && <div className="tl-cat-body">{rows.map((r) => <TlTestRow key={group.cat + r.name} row={r} profile={profile} logs={logs} />)}</div>}
        </div>
      </div>
    </div>
  );
}

/* ---- overview summary card ---------------------------------------------- */
function TlOverview({ counts }) {
  const pct = counts.total ? Math.round((counts.uptodate / counts.total) * 100) : 0;
  const stat = (k, n) => (
    <div className="tl-ov-stat">
      <span className="tl-ov-num" style={{ color: TL_STATUS[k].color }}>{n}</span>
      <span className="tl-ov-lab">{TL_STATUS[k].label}</span>
    </div>
  );
  return (
    <div className="tl-ov">
      <div className="tl-ov-top">
        <div>
          <div className="tl-ov-title">Monitoring overview</div>
          <div className="tl-ov-cap">{counts.uptodate} of {counts.total} tracked tests up to date</div>
        </div>
        <div className="tl-ring" style={{ '--p': pct }}><span>{pct}<small>%</small></span></div>
      </div>
      <div className="tl-ov-bar"><span style={{ width: pct + '%' }} /></div>
      <div className="tl-ov-stats">
        {stat('uptodate', counts.uptodate)}
        {stat('duesoon', counts.duesoon)}
        {stat('overdue', counts.overdue)}
        {stat('never', counts.never)}
      </div>
    </div>
  );
}

function MonTimetable({ profile, logs, open, onToggle }) {
  logs = logs || [];
  const [query, setQuery] = React.useState('');
  const [chip, setChip] = React.useState('All');
  const [mineOnly, setMineOnly] = React.useState(true);
  const age = profile ? profile.age : null;
  const q = query.trim().toLowerCase();

  const toggle = () => { if (onToggle) onToggle(); };

  // build the filtered groups
  const groups = TL_DATA
    .filter((g) => chip === 'All' || g.chip === chip)
    .map((g) => ({
      ...g,
      rows: g.rows.filter((r) => {
        if (mineOnly && age != null && !tlApplies(r, profile)) return false;
        if (q && !(r.name + ' ' + g.cat + ' ' + (r.note || '')).toLowerCase().includes(q)) return false;
        return true;
      }),
    }))
    .filter((g) => g.rows.length);

  // overview counts — across tracked + applicable tests only
  const counts = React.useMemo(() => {
    const c = { total: 0, uptodate: 0, duesoon: 0, overdue: 0, never: 0 };
    TL_DATA.forEach((g) => g.rows.forEach((r) => {
      if (!r.id) return;
      if (age != null && !tlApplies(r, profile)) return;
      const s = tlRowState(r, profile, logs);
      if (!s.tracked) return;
      c.total++;
      if (c[s.key] != null) c[s.key]++;
    }));
    return c;
  }, [profile, logs, age]);

  // accordion open-state: open categories with attention by default
  const [openCats, setOpenCats] = React.useState(null);
  React.useEffect(() => {
    if (openCats !== null) return;
    const init = {};
    TL_DATA.forEach((g) => {
      const attn = g.rows.some((r) => { const s = tlRowState(r, profile, logs); return s.tracked && (s.key === 'overdue' || s.key === 'duesoon' || s.key === 'never'); });
      init[g.cat] = attn;
    });
    setOpenCats(init);
  }, [profile, logs]);
  const oc = openCats || {};
  const toggleCat = (cat) => setOpenCats((prev) => ({ ...(prev || {}), [cat]: !(prev || {})[cat] }));
  const allOpen = groups.length > 0 && groups.every((g) => oc[g.cat]);
  const setAll = (v) => setOpenCats(() => { const o = {}; TL_DATA.forEach((g) => { o[g.cat] = v; }); return o; });

  // when searching, force-open matching categories
  const effOpen = (cat) => (q ? true : !!oc[cat]);

  return (
    <div className="tt-wrap" style={{ marginBottom: 14 }}>
      <button className="tt-head" onClick={toggle} aria-expanded={open}>
        <span className="tt-head-leaf"><Icon name="calendar" size={17} color="var(--sky-deep)" /></span>
        <span className="tt-head-tx">
          <span className="tt-head-title">General Timeline for Clinical &amp; Laboratory Evaluation</span>
          <span className="tt-head-sub">Your personalised TIF monitoring roadmap · tap to {open ? 'collapse' : 'expand'}</span>
        </span>
        <Icon name="chevD" size={19} color="var(--ink-3)" style={{ flex: 'none', transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .22s' }} />
      </button>

      {open && (
        <div className="tt-body">
          <TlOverview counts={counts} />

          {/* search */}
          <div className="card-flat row" style={{ gap: 9, padding: '9px 12px', marginBottom: 10 }}>
            <Icon name="search" size={16} color="var(--ink-3)" />
            <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search tests…" style={{ flex: 1, minWidth: 0, border: 'none', background: 'none', outline: 'none', fontFamily: 'inherit', fontSize: 13.5, color: 'var(--ink)' }} />
            {query && <button className="icon-btn" style={{ width: 24, height: 24, flex: 'none', background: 'var(--surface-2)' }} onClick={() => setQuery('')} aria-label="Clear"><Icon name="x" size={12} /></button>}
          </div>

          {/* filter chips */}
          <div className="tl-chips">
            {TL_CHIPS.map((c) => (
              <button key={c} className={'chip' + (chip === c ? ' on' : '')} onClick={() => setChip(c)}>{c}</button>
            ))}
          </div>

          {/* controls row */}
          <div className="tl-controls">
            {age != null && (
              <button className={'tl-toggle' + (mineOnly ? ' on' : '')} onClick={() => setMineOnly((v) => !v)}>
                <Icon name={mineOnly ? 'check' : 'plus'} size={13} color={mineOnly ? '#fff' : 'var(--ink-2)'} sw={3} />
                {mineOnly ? `For age ${age}` : 'Show all ages'}
              </button>
            )}
            <button className="tl-link" onClick={() => setAll(!allOpen)}>{allOpen ? 'Collapse all' : 'Expand all'}</button>
          </div>

          {/* accordions */}
          {groups.length === 0 ? (
            <div className="card-flat" style={{ padding: '16px', textAlign: 'center' }}><span className="body" style={{ fontSize: 13 }}>Nothing matches{q ? ` “${query}”` : ''}.</span></div>
          ) : (
            <div className="tl-list">
              {groups.map((g) => (
                <TlCategory key={g.cat} group={g} rows={g.rows} open={effOpen(g.cat)} onToggle={() => toggleCat(g.cat)} profile={profile} logs={logs} />
              ))}
            </div>
          )}

          {/* legend */}
          <div className="tl-legend">
            {['uptodate', 'duesoon', 'overdue', 'never', 'reference'].map((k) => (
              <span key={k}><span className="tl-status-dot" style={{ background: TL_STATUS[k].color }} />{TL_STATUS[k].label}</span>
            ))}
          </div>
          <div className="dmeta muted" style={{ textAlign: 'center', padding: '4px 8px 2px', lineHeight: 1.5 }}>
            Reference schedule from the TIF guidelines. Your care team sets the plan that is right for you.
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { MonTimetable, TL_DATA });
