// movement.jsx  v9 - Axis 动作筛查工作台。
// 数字化 C-PS Integrated Movement Assessment:逐测试 Pass/Fail + 标记代偿区域 →
// 自动从动作库(source:C-PS)按区域荐 Phase-1 纠正动作。结果存 FieldDataStore.screenResults。
// 入口:个人页 movement-latest bento 模块 → view 'movement-screen'。

const { useState: msS, useEffect: msE, useMemo: msM } = React;

function msToday() { return new Date().toISOString().slice(0, 10); }
// ── MovementScreenView ──────────────────────────────────────────────────────
function MovementScreenView({ athlete, groups = [], seasons = [], onBack }) {
  const FS = window.FieldDataStore;
  const [screen, setScreen] = msS(null);
  const [exercises, setExercises] = msS([]);
  const [date, setDate] = msS(msToday());
  const [results, setResults] = msS({});   // { testName: { status, regions:[] } }
  const [savedAt, setSavedAt] = msS(null);
  const [loaded, setLoaded] = msS(false);

  // load template + corrective library
  msE(() => {
    let alive = true;
    (async () => {
      if (!FS) return;
      try {
        await FS.init('default');
        const screens = await FS.listMovementScreens();
        const exs = await FS.listExercises();
        if (!alive) return;
        setScreen(screens.find(s => s.id === 'cps_ima') || screens[0] || null);
        setExercises(exs);
      } catch (e) { console.warn('screen load', e); }
    })();
    return () => { alive = false; };
  }, [FS]);

  // load existing result for athlete+date
  msE(() => {
    let alive = true;
    if (!screen) return;
    (async () => {
      const r = await FS.getScreenResult(screen.id, athlete.id, date);
      if (alive) { setResults(r?.results || {}); setLoaded(true); }
    })();
    return () => { alive = false; };
  }, [screen, athlete?.id, date]);

  const persist = (next) => {
    if (!screen) return;
    FS.saveScreenResult({ screenId: screen.id, athleteId: athlete.id, date, results: next }).then(() => setSavedAt(Date.now()));
  };
  const setStatus = (test, status) => setResults(prev => {
    const cur = prev[test] || { status: null, regions: [] };
    const next = { ...prev, [test]: { ...cur, status: cur.status === status ? null : status } };
    persist(next); return next;
  });
  const toggleRegion = (test, region) => setResults(prev => {
    const cur = prev[test] || { status: 'fail', regions: [] };
    const regions = cur.regions.includes(region) ? cur.regions.filter(r => r !== region) : [...cur.regions, region];
    const next = { ...prev, [test]: { ...cur, status: 'fail', regions } };
    persist(next); return next;
  });

  // ── Compensations (代偿项) · collapsible per-test checklist; checked items derive flagged regions ──
  const COMPS = (window.CPS_KNOWLEDGE && window.CPS_KNOWLEDGE.compensations) || {};
  const [compOpen, setCompOpen] = msS({});
  const toggleComp = (test, list, item) => setResults(prev => {
    const cur = prev[test] || { status: 'fail', regions: [] };
    const comps = cur.comps || [];
    const nextComps = comps.includes(item) ? comps.filter(x => x !== item) : [...comps, item];
    const regions = [...new Set(nextComps.flatMap(it => (list.find(c => c.item === it) || {}).regions || []))];
    const next = { ...prev, [test]: { ...cur, status: 'fail', comps: nextComps, regions } };
    persist(next); return next;
  });

  // ── Breakdown drill-down (per failed test) ──
  const [bdOpen, setBdOpen] = msS({});
  const BD = (window.CPS_KNOWLEDGE && window.CPS_KNOWLEDGE.breakdowns) || null;
  const sectionsForTest = (t) => {
    const r = results[t.test] || {};
    const regs = (r.regions && r.regions.length ? r.regions : t.regions) || [];
    return [...new Set(regs.map(reg => BD && BD.regionSection[reg]).filter(Boolean))];
  };
  const toggleBdItem = (test, label) => setResults(prev => {
    const cur = prev[test] || { status: 'fail', regions: [] };
    const bd = cur.breakdown || [];
    const next = { ...prev, [test]: { ...cur, breakdown: bd.includes(label) ? bd.filter(x => x !== label) : [...bd, label] } };
    persist(next); return next;
  });
  // limiter-type hint from which breakdown categories have ≥1 flagged sub-test
  const BD_HINT = {
    'Mobility': '活动度受限 → 先做活动度/关节松动', 'ROM': '活动度受限 → 先做活动度/关节松动',
    'Joint Mobility': '关节活动受限 → 关节松动', 'Soft Tissue': '软组织受限 → 软组织处理/放松',
    'Motor Control': '运动控制不足 → Phase-1 RS 纠正(右侧已荐)', 'Manual Muscle Test': '肌力不足 → 进阶强化',
  };

  // aggregate flagged corrective regions across failed tests
  const flagged = msM(() => {
    const set = new Set();
    (screen?.tests || []).forEach(t => {
      const r = results[t.test];
      if (r && r.status === 'fail') (r.regions && r.regions.length ? r.regions : t.regions).forEach(reg => set.add(reg));
    });
    return [...set];
  }, [screen, results]);

  // suggested C-PS correctives · phase-switchable (默认 Phase 1 起步)
  // 远端关节(膝/踝)在 C-PS 体系无独立手册 → 经髋(Hip)处理:把这些 region 归并到 Hip 的纠正动作。
  const [suggPhase, setSuggPhase] = msS(1);
  const REGION_SRC = (window.CPS_KNOWLEDGE && window.CPS_KNOWLEDGE.regionCorrectiveSource) || {};
  const suggestions = msM(() => {
    const groups = {};   // srcRegion -> { covers:[flaggedRegions], list:[ex] }
    flagged.forEach(reg => {
      const src = REGION_SRC[reg] || reg;
      (groups[src] = groups[src] || { covers: [], list: [] }).covers.push(reg);
    });
    Object.keys(groups).forEach(src => {
      groups[src].list = exercises
        .filter(e => e.source === 'C-PS' && e.region === src && (e.phase === suggPhase || (suggPhase === 1 && e.phase == null)))
        .slice(0, 8);
    });
    return groups;
  }, [flagged, exercises, suggPhase]);

  const tests = screen?.tests || [];
  const passN = tests.filter(t => results[t.test]?.status === 'pass').length;
  const failN = tests.filter(t => results[t.test]?.status === 'fail').length;

  return (
    <main className="movement-workbench-page" data-movement-screen-workbench data-ai-contract="movement-screen-v1">
      <header className="movement-commandbar">
        <button className="btn movement-back" onClick={onBack}>← 返回运动员</button>
        <div className="movement-athlete-context">
          <span>当前运动员</span>
          <strong>{athlete?.name}</strong>
        </div>
        <label className="movement-date-field">
          <span>筛查日期</span>
          <input type="date" value={date} onChange={e => setDate(e.target.value)} />
        </label>
        <span className={`movement-save-state${savedAt ? ' saved' : ''}`}>
          {savedAt ? '已保存 ✓' : (loaded ? '就绪' : '加载中…')}
        </span>
      </header>

      {!screen ? (
        <div className="movement-empty-state">未找到筛查模板（C-PS IMA 尚未入库）。</div>
      ) : (
        <div className="movement-workbench-content">
          <section className="movement-main-column">
            <section className="movement-summary" aria-label="动作筛查进度">
              <div className="movement-summary-progress">
                <span>{screen.name || 'Integrated Movement Assessment'}</span>
                <strong>已完成 {passN + failN} / {tests.length} 项</strong>
                <div aria-hidden="true"><i style={{ width: `${tests.length ? Math.round(((passN + failN) / tests.length) * 100) : 0}%` }} /></div>
              </div>
              <div><span>通过</span><strong className="positive">{passN}</strong><small>人工确认</small></div>
              <div><span>需关注</span><strong className="warning">{failN}</strong><small>含代偿观察</small></div>
              <div><span>未评估</span><strong>{Math.max(0, tests.length - passN - failN)}</strong><small>等待记录</small></div>
            </section>

            <section className="movement-screen-card">
              <header className="movement-section-head">
                <strong>筛查项目</strong>
                <span>逐项记录，不自动生成诊断或回归资格</span>
              </header>
              <div className="movement-screen-list">
                {tests.map((t, index) => {
                  const r = results[t.test] || {};
                  const comps = COMPS[t.test];
                  const selectedComps = r.comps || [];
                  const compIsOpen = compOpen[t.test] !== false;
                  const sections = sectionsForTest(t);
                  const breakdownOpen = !!bdOpen[t.test];
                  const selectedBreakdown = r.breakdown || [];
                  const limiterCats = [...new Set(selectedBreakdown.map(x => x.split(' · ')[0]))];
                  return (
                    <article
                      key={t.test}
                      className={`movement-screen-row ${r.status || 'pending'}`}
                      data-screen-test={t.test}
                      data-screen-status={r.status || 'pending'}
                    >
                      <div className="movement-screen-row-head">
                        <span className="movement-screen-number">{String(index + 1).padStart(2, '0')}</span>
                        <div className="movement-screen-title">
                          <strong>{t.test}</strong>
                          <span>{(t.regions || []).join(' · ') || '动作质量与控制观察'}</span>
                        </div>
                        <div className="movement-status-actions">
                          {[['pass', '通过'], ['fail', '需关注']].map(([value, label]) => (
                            <button
                              key={value}
                              className={r.status === value ? `on ${value}` : ''}
                              aria-pressed={r.status === value}
                              onClick={() => setStatus(t.test, value)}
                            >
                              {label}
                            </button>
                          ))}
                        </div>
                      </div>

                      {r.status === 'fail' && (
                        <div className="movement-screen-evidence">
                          <div className="movement-observation-column">
                            {!comps ? (
                              <section className="movement-evidence-group">
                                <div className="movement-evidence-label">观察到的代偿区域</div>
                                <div className="movement-chip-list">
                                  {(t.regions || []).map(region => {
                                    const on = (r.regions || []).includes(region);
                                    return (
                                      <button
                                        key={region}
                                        className={`movement-chip${on ? ' on' : ''}`}
                                        data-compensation-region={region}
                                        aria-pressed={on}
                                        onClick={() => toggleRegion(t.test, region)}
                                      >
                                        {on ? '✓ ' : ''}{region}
                                      </button>
                                    );
                                  })}
                                </div>
                              </section>
                            ) : (
                              <section className="movement-evidence-group">
                                <button
                                  className="movement-evidence-toggle"
                                  aria-expanded={compIsOpen}
                                  onClick={() => setCompOpen(open => ({ ...open, [t.test]: !(open[t.test] !== false) }))}
                                >
                                  <span>观察到的代偿</span>
                                  <small>{selectedComps.length ? `已选 ${selectedComps.length}` : '勾选人工观察'}</small>
                                  <b>{compIsOpen ? '收起' : '展开'}</b>
                                </button>
                                {compIsOpen && (
                                  <div className="movement-chip-list">
                                    {comps.map(comp => {
                                      const on = selectedComps.includes(comp.item);
                                      return (
                                        <button
                                          key={comp.item}
                                          className={`movement-chip warning${on ? ' on' : ''}`}
                                          data-compensation-item={comp.item}
                                          title={(comp.regions || []).join(' · ')}
                                          aria-pressed={on}
                                          onClick={() => toggleComp(t.test, comps, comp.item)}
                                        >
                                          {on ? '✓ ' : ''}{comp.item}
                                        </button>
                                      );
                                    })}
                                  </div>
                                )}
                              </section>
                            )}
                            {(r.regions || []).length > 0 && (
                              <section className="movement-evidence-group">
                                <div className="movement-evidence-label">自动关联区域，仅用于检索动作库</div>
                                <div className="movement-chip-list">
                                  {(r.regions || []).map(region => (
                                    <span key={region} className="movement-chip linked" data-linked-region={region}>{region}</span>
                                  ))}
                                </div>
                              </section>
                            )}
                          </div>

                          {BD && sections.length > 0 && (
                            <section className="movement-breakdown">
                              <button
                                className="movement-breakdown-toggle"
                                aria-expanded={breakdownOpen}
                                onClick={() => setBdOpen(open => ({ ...open, [t.test]: !open[t.test] }))}
                              >
                                <span>细分验证</span>
                                <small>{selectedBreakdown.length ? `已选 ${selectedBreakdown.length}` : '可选人工验证项'}</small>
                                <b>{breakdownOpen ? '收起' : '展开'}</b>
                              </button>
                              {breakdownOpen && (
                                <div className="movement-breakdown-body">
                                  {sections.map(section => (
                                    <div key={section} className="movement-breakdown-section">
                                      <div className="movement-evidence-label">{section === 'Upper' ? '上肢 / 躯干' : '下肢'}</div>
                                      {Object.entries(BD[section]).map(([category, list]) => (
                                        <div key={category} className="movement-breakdown-category">
                                          <strong>{category}</strong>
                                          <div className="movement-chip-list">
                                            {list.map(item => {
                                              const label = `${category} · ${item}`;
                                              const on = selectedBreakdown.includes(label);
                                              return (
                                                <button
                                                  key={item}
                                                  className={`movement-chip warning${on ? ' on' : ''}`}
                                                  data-breakdown-item={label}
                                                  aria-pressed={on}
                                                  onClick={() => toggleBdItem(t.test, label)}
                                                >
                                                  {on ? '✓ ' : ''}{item}
                                                </button>
                                              );
                                            })}
                                          </div>
                                        </div>
                                      ))}
                                    </div>
                                  ))}
                                  {limiterCats.length > 0 && (
                                    <div className="movement-limiter-notes">
                                      {limiterCats.map(category => <div key={category}>{BD_HINT[category] || category}</div>)}
                                    </div>
                                  )}
                                </div>
                              )}
                              <p>细分项是人工观察记录，不代表医学诊断。选择结果只用于缩小候选动作范围。</p>
                            </section>
                          )}
                        </div>
                      )}
                    </article>
                  );
                })}
              </div>
            </section>
          </section>

          <aside className="movement-context-column">
            <section className="movement-context-card movement-candidates" data-corrective-candidates>
              <header>
                <strong>纠正动作候选</strong>
                <span>C-PS</span>
              </header>
              <div className="movement-phase-tabs">
                {[1, 2, 3, 4].map(phase => (
                  <button
                    key={phase}
                    className={suggPhase === phase ? 'on' : ''}
                    aria-pressed={suggPhase === phase}
                    onClick={() => setSuggPhase(phase)}
                  >
                    P{phase}
                  </button>
                ))}
              </div>
              <div className="movement-candidate-note">
                由人工标记的代偿和细分项匹配动作库。使用者决定是否采纳并写入训练或康复安排。
              </div>
              {flagged.length === 0 ? (
                <div className="movement-candidate-empty">标记“需关注”并记录代偿后，这里会按关联区域显示 Phase {suggPhase} 候选动作。</div>
              ) : (
                <div className="movement-region-list">
                  {Object.entries(suggestions).map(([sourceRegion, group]) => {
                    const distal = group.covers.filter(region => region !== sourceRegion);
                    return (
                      <section key={sourceRegion} className="movement-region-block" data-corrective-region={sourceRegion}>
                        <header>
                          <strong>{sourceRegion}</strong>
                          {distal.length > 0 && <span>覆盖 {distal.join(' / ')}</span>}
                        </header>
                        {group.list.length ? group.list.map((exercise, index) => (
                          <div
                            key={`${exercise.id || exercise.name}-${index}`}
                            className="movement-candidate-row"
                            data-corrective-candidate={exercise.id || exercise.name}
                            data-corrective-phase={suggPhase}
                          >
                            <div>
                              <strong>{exercise.name}</strong>
                              <span>{exercise.position || `Phase ${suggPhase}`}</span>
                            </div>
                            <b>{exercise.sets}×{exercise.reps}</b>
                          </div>
                        )) : (
                          <div className="movement-candidate-empty">该区域 Phase {suggPhase} 暂无已入库动作。</div>
                        )}
                      </section>
                    );
                  })}
                </div>
              )}
            </section>
            <section className="movement-context-card movement-system-boundary">
              <header><strong>系统边界</strong></header>
              <p>系统保存观察事实、人工选择与动作库匹配结果，不自动诊断损伤，不判断回归资格，也不替使用者开具训练处方。</p>
            </section>
          </aside>
        </div>
      )}
    </main>
  );
}

Object.assign(window, { MovementScreenView });
