// Structured Decision Case + explicit action confirmation UI.
// It renders deterministic evidence and calls only ConfirmedActionExecutor.
const AI_DECISION_UI_CSS = `
.axis-ai-panel.decision-mode{width:min(960px,calc(100vw - 250px))}
.aic-case{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:10px}.aic-main,.aic-side{display:grid;gap:10px;align-content:start}.aic-question{padding:12px 14px;border-radius:11px;background:#303b4d;color:#fff}.aic-question small{display:block;color:#c7ced7;font:8px var(--font-mono);text-transform:uppercase}.aic-question p{margin:4px 0 0;font-size:11px}
.aic-section,.aic-side-card{border:1px solid #e0e4ea;border-radius:11px;background:#fff;padding:13px}.aic-section-head{display:flex;gap:9px;align-items:flex-start;margin-bottom:10px}.aic-index{width:26px;height:26px;display:grid;place-items:center;flex:0 0 auto;border:1px solid #dfe3e8;border-radius:7px;background:#f4f5f7;color:#6e7887;font:9px var(--font-mono)}.aic-section h3,.aic-side-card h3{margin:0;font-size:14px}.aic-section-head p,.aic-side-card>p{margin:3px 0 0;color:#7b8595;font-size:10.5px;line-height:1.45}
.aic-observations{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}.aic-observation{padding:11px;border-radius:8px;background:#f6f7f9}.aic-observation small,.aic-observation b,.aic-observation span{display:block}.aic-observation small{color:#7c8797;font-size:9.5px}.aic-observation b{margin-top:5px;font-size:19px}.aic-observation span{margin-top:4px;color:#687384;font-size:10.5px;line-height:1.5}
.aic-evidence{display:grid;gap:7px}.aic-evidence-row{display:grid;grid-template-columns:68px minmax(0,1fr);gap:9px;padding:9px;border:1px solid #e5e8ed;border-radius:8px}.aic-evidence-row>span:first-child{height:22px;display:grid;place-items:center;border-radius:5px;background:#f1f3f5;color:#697485;font:8.5px var(--font-mono)}.aic-evidence-row b,.aic-evidence-row small{display:block}.aic-evidence-row b{font-size:11.5px}.aic-evidence-row small{margin-top:3px;color:#707b8b;font-size:10px;line-height:1.5;overflow-wrap:anywhere}
.aic-interpretations{display:grid;grid-template-columns:1fr 1fr;gap:8px}.aic-interpretations article{padding:10px;border:1px solid #e3e6eb;border-radius:8px}.aic-interpretations b{font-size:11.5px}.aic-interpretations p{margin:4px 0 0;color:#687384;font-size:10.5px;line-height:1.55}.aic-limitations{margin-top:8px;padding:9px;border-left:3px solid #aab2bd;background:#f5f6f8;color:#687384;font-size:10.5px;line-height:1.5}.aic-limitations div+div{margin-top:5px}
.aic-option{display:grid;grid-template-columns:18px minmax(0,1fr) auto;gap:8px;align-items:start;padding:9px 0;border-top:1px solid #e6e9ed;cursor:pointer}.aic-option:first-of-type{border-top:0}.aic-option input{margin-top:3px;accent-color:#394556}.aic-option b,.aic-option small{display:block}.aic-option b{font-size:11.5px}.aic-option small{margin-top:3px;color:#707b8b;font-size:10px;line-height:1.5}.aic-pill{padding:4px 7px;border:1px solid #dde1e6;border-radius:999px;color:#697485;font-size:9px;white-space:nowrap}.aic-case-actions{display:flex;justify-content:flex-end;gap:7px;margin-top:10px}.aic-btn{min-height:36px;padding:0 12px;border:1px solid #d9dee5;border-radius:8px;background:#fff;color:#3f4a5b;font-size:11px;cursor:pointer}.aic-btn.primary{border-color:#303b4d;background:#303b4d;color:#fff;font-weight:700}.aic-btn.danger{color:#8b4f4c}.aic-btn:disabled{opacity:.42;cursor:not-allowed}
.aic-scope{display:grid;gap:8px;margin-top:11px}.aic-scope div{display:flex;justify-content:space-between;gap:8px;color:#707b8b;font-size:10px;line-height:1.4}.aic-scope b{color:#4d5868;text-align:right}.aic-quality{margin-top:9px;padding:9px;border-radius:8px;background:#f5f6f8;color:#687384;font-size:10px;line-height:1.55}.aic-error{margin-top:8px;padding:9px;border:1px solid #ebcecc;border-radius:8px;background:#fff5f5;color:#9b504d;font-size:10.5px}
.aia-overlay{position:fixed;inset:0;z-index:180;display:grid;place-items:center;padding:20px;background:rgba(28,36,48,.38);backdrop-filter:blur(3px)}.aia-dialog{width:min(820px,calc(100vw - 40px));max-height:calc(100vh - 40px);overflow:auto;border:1px solid #d5dae1;border-radius:15px;background:#fff;box-shadow:0 24px 80px rgba(24,32,44,.22)}.aia-head,.aia-foot{display:flex;align-items:center;gap:9px;padding:14px 16px}.aia-head{border-bottom:1px solid #e1e5ea}.aia-head>button{margin-left:auto}.aia-head b,.aia-head small{display:block}.aia-head b{font-size:15px}.aia-head small{margin-top:3px;color:#707b8b;font-size:10.5px}.aia-body{display:grid;grid-template-columns:minmax(0,1fr) 260px;gap:0}.aia-changes{padding:16px;border-right:1px solid #e1e5ea}.aia-side{padding:16px}.aia-change{display:grid;grid-template-columns:110px minmax(0,1fr);gap:11px;padding:11px 0;border-bottom:1px solid #e8ebef}.aia-change:first-child{padding-top:0}.aia-change>span{color:#748091;font-size:10px}.aia-change>div{font-size:11.5px}.aia-change b,.aia-change small{display:block}.aia-change small{margin-top:4px;color:#707b8b;font-size:10px;line-height:1.55}.aia-edit{width:100%;min-height:38px;margin-top:8px;border:1px solid #d9dee5;border-radius:8px;padding:0 10px;font-size:12px}.aia-digest{padding:10px;border-radius:8px;background:#f4f5f7;font:9.5px var(--font-mono);overflow-wrap:anywhere}.aia-evidence{max-height:150px;overflow:auto;margin-top:9px;color:#6f7a8a;font-size:9.5px;line-height:1.45}.aia-evidence div+div{margin-top:5px}.aia-ack{display:flex;gap:8px;margin-top:12px;padding:11px;border:1px solid #dfe3e8;border-radius:9px;color:#5f6a79;font-size:10.5px;line-height:1.45}.aia-ack input{margin-top:2px;accent-color:#394556}.aia-foot{justify-content:flex-end;border-top:1px solid #e1e5ea}.aia-receipt{padding:20px}.aia-receipt h3{margin:0;color:#326b51;font-size:16px}.aia-receipt p{color:#687384;font-size:11.5px}.aia-receipt dl{display:grid;gap:8px}.aia-receipt div{display:grid;grid-template-columns:120px 1fr;gap:8px;font-size:10.5px}.aia-receipt dt{color:#7d8796}.aia-receipt dd{margin:0;overflow-wrap:anywhere}
@media(max-width:1000px){.axis-ai-panel.decision-mode{width:min(720px,calc(100vw - 76px))}.aic-case{grid-template-columns:1fr}.aic-side{grid-template-columns:1fr 1fr}.aia-body{grid-template-columns:1fr}.aia-changes{border-right:0;border-bottom:1px solid #e1e5ea}}@media(max-width:700px){.aic-observations,.aic-interpretations,.aic-side{grid-template-columns:1fr}.aia-change{grid-template-columns:1fr}}
`;

function AiActionConfirmation({ proposal: initialProposal, actions, onClose, onNavigate }) {
  const [proposal, setProposal] = React.useState(initialProposal);
  const [name, setName] = React.useState(initialProposal?.payload?.name || '');
  const [acknowledged, setAcknowledged] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');

  const revise = async () => {
    if (!name.trim() || !actions?.revise) return;
    setBusy(true); setError('');
    try {
      const payload = {
        ...proposal.payload,
        name:name.trim(),
        ...(proposal.kind === 'training_plan_draft'
          ? { program:{ ...(proposal.payload.program || {}), name:name.trim() } }
          : {}),
      };
      const next = await actions.revise({
        proposalId:proposal.id,
        expectedRevision:proposal.revision,
        editedBy:'local-user',
        patch:{ payload },
      });
      setProposal(next);
      setAcknowledged(false);
    } catch (cause) { setError(cause?.message || '草案更新失败。'); }
    finally { setBusy(false); }
  };

  const confirm = async () => {
    setBusy(true); setError('');
    try {
      const result = await actions.confirmAndExecute({
        proposalId:proposal.id,
        proposalDigest:proposal.proposalDigest,
        expectedRevision:proposal.revision,
        confirmedBy:'local-user',
        acknowledgement:window.AiActionProposalContract.ACKNOWLEDGEMENT,
      });
      setProposal(result);
    } catch (cause) { setError(cause?.message || '草案写入失败。'); }
    finally { setBusy(false); }
  };

  const cancel = async () => {
    if (proposal.status === 'awaiting_confirmation') {
      try {
        await actions.cancel({ proposalId:proposal.id, expectedRevision:proposal.revision, cancelledBy:'local-user' });
      } catch (_) {}
    }
    onClose();
  };

  const targetLabel = proposal.kind === 'training_plan_draft'
    ? '训练计划草稿'
    : proposal.kind === 'report_draft' ? '个体报告编辑草稿' : proposal.kind;
  const route = proposal.kind === 'training_plan_draft' ? 'training' : 'report';
  return <div className="aia-overlay" role="dialog" aria-modal="true" aria-label="确认 AI 动作">
    <section className="aia-dialog" data-ai-action-status={proposal.status}>
      {proposal.status === 'succeeded' ? <div className="aia-receipt" data-ai-action-receipt>
        <h3>草案已确认写入</h3>
        <p>写入的是可编辑草案，不是已发布计划、已确认结论或对外报告。</p>
        <dl>
          <div><dt>目标</dt><dd>{targetLabel}</dd></div>
          <div><dt>记录</dt><dd>{proposal.result?.recordId || '—'}</dd></div>
          <div><dt>目标 revision</dt><dd>{proposal.result?.revision || '—'}</dd></div>
          <div><dt>提案</dt><dd>{proposal.id}</dd></div>
          <div><dt>幂等键</dt><dd>{proposal.idempotencyKey}</dd></div>
        </dl>
        <div className="aic-case-actions"><button className="aic-btn" onClick={onClose}>关闭</button><button className="aic-btn primary" onClick={() => { onClose(); onNavigate?.(route); }}>打开并继续编辑</button></div>
      </div> : <>
        <header className="aia-head"><div><b>确认 AI 动作</b><small>尚未写入业务记录 · 绑定 proposal revision {proposal.revision}</small></div><button className="aic-btn" onClick={cancel}>关闭</button></header>
        <div className="aia-body">
          <section className="aia-changes">
            <div className="aia-change"><span>写入目标</span><div><b>{targetLabel}</b><small>{proposal.target.athleteId} {proposal.target.season ? `· ${proposal.target.season}` : ''}</small></div></div>
            <div className="aia-change"><span>即将写入</span><div><b>{proposal.payload.name || '报告叙事草稿'}</b><small>{proposal.impactSummary}</small>
              {proposal.kind === 'training_plan_draft'&&<><input className="aia-edit" value={name} onChange={event=>setName(event.target.value)} aria-label="训练草案名称"/><button className="aic-btn" style={{marginTop:7}} onClick={revise} disabled={busy||name.trim()===proposal.payload.name}>应用编辑</button></>}
            </div></div>
            <div className="aia-change"><span>不会发生</span><div><b>不会发布、覆盖历史或确认科学结论</b><small>本动作只创建/更新可编辑草案。后续发布仍由原工作流控制。</small></div></div>
            <div className="aia-change"><span>冲突保护</span><div><b>{proposal.expectedTargetRevision == null?'新草案 / 无既有目标':'目标 revision '+proposal.expectedTargetRevision}</b><small>目标版本变化时适配器会拒绝写入，不会静默覆盖。</small></div></div>
          </section>
          <aside className="aia-side">
            <b style={{fontSize:10}}>证据引用</b>
            <div className="aia-evidence">{(proposal.evidenceRefs||[]).map((ref,index)=><div key={index}>{typeof ref==='string'?ref:(ref.ref||JSON.stringify(ref))}</div>)}</div>
            <p style={{color:'#788394',fontSize:8.5}}>完整提案摘要</p><div className="aia-digest">{proposal.proposalDigest}</div>
            <label className="aia-ack"><input type="checkbox" checked={acknowledged} onChange={event=>setAcknowledged(event.target.checked)}/><span>我已核对最终写入目标和值，确认仅保存为草案。</span></label>
            {error&&<div className="aic-error">{error}</div>}
          </aside>
        </div>
        <footer className="aia-foot"><button className="aic-btn" onClick={cancel}>取消提案</button><button className="aic-btn primary" disabled={!acknowledged||busy} onClick={confirm}>{busy?'写入中…':'确认并保存草案'}</button></footer>
      </>}
    </section>
  </div>;
}

function AiDecisionCaseView({ decisionCase, decisionTools, onNavigate }) {
  const [selectedOptionId, setSelectedOptionId] = React.useState(decisionCase.options?.[0]?.id || '');
  const [proposal, setProposal] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');
  const option = decisionCase.options.find(row=>row.id===selectedOptionId) || null;
  const summary = decisionCase.analyses?.[0]?.result || {};
  const formProposal = async () => {
    if (!option?.actionKind || !decisionTools?.prepareAction || !decisionTools?.actions) return;
    setBusy(true); setError('');
    try {
      const input = await decisionTools.prepareAction(decisionCase, option);
      setProposal(await decisionTools.actions.propose(input));
    } catch (cause) { setError(cause?.message || '无法形成动作提案。'); }
    finally { setBusy(false); }
  };
  const observationValue = row => {
    if (row.id==='latest_metric_change') return row.values?.changePercent == null ? '—' : `${Number(row.values.changePercent).toFixed(1)}%`;
    if (row.id==='training_exposure') return row.values?.totalSessionLoad == null ? `${row.values?.sessionCount||0} 次` : Number(row.values.totalSessionLoad).toFixed(0);
    return String(row.values?.activeCount ?? '—');
  };
  return <>
    <style>{AI_DECISION_UI_CSS}</style>
    <div className="aic-case" data-ai-decision-case={decisionCase.id}>
      <div className="aic-main">
        <div className="aic-question"><small>User Question</small><p>{decisionCase.question}</p></div>
        <section className="aic-section">
          <div className="aic-section-head"><span className="aic-index">01</span><div><h3>发生了什么</h3><p>只陈述当前数据事实。</p></div></div>
          <div className="aic-observations">{decisionCase.observations.map(row=><article className="aic-observation" key={row.id}><small>{row.id.replaceAll('_',' ')}</small><b>{observationValue(row)}</b><span>{row.statement}</span></article>)}</div>
        </section>
        <section className="aic-section">
          <div className="aic-section-head"><span className="aic-index">02</span><div><h3>证据与引用</h3><p>业务记录、计算和知识来源保持分层。</p></div></div>
          <div className="aic-evidence">
            {decisionCase.observations.map(row=><div className="aic-evidence-row" key={'data-'+row.id}><span>DATA</span><span><b>{row.statement}</b><small>{(row.sourceRefs||[]).map(ref=>typeof ref==='string'?ref:ref.ref).filter(Boolean).slice(0,2).join(' · ')||'结构化业务记录'}</small></span></div>)}
            {decisionCase.knowledgeEvidence.map(row=><div className="aic-evidence-row" key={row.ref}><span>{row.scope==='personal'?'PERSONAL':'UNIVERSAL'}</span><span><b>{row.title}</b><small>{row.excerpt} · {row.citation?.locator?.section||`page ${row.citation?.locator?.page||'—'}`}</small></span></div>)}
          </div>
        </section>
        <section className="aic-section">
          <div className="aic-section-head"><span className="aic-index">03</span><div><h3>可以解释什么，不能解释什么</h3><p>不把共同时间窗口写成因果关系。</p></div></div>
          <div className="aic-interpretations">{decisionCase.interpretations.map(row=><article key={row.id}><b>{row.status==='attention'?'需要复核':'当前解释'}</b><p>{row.statement}</p></article>)}</div>
          <div className="aic-limitations">{decisionCase.limitations.map(row=><div key={row.code}><b>{row.code}</b> · {row.statement}</div>)}</div>
        </section>
        <section className="aic-section">
          <div className="aic-section-head"><span className="aic-index">04</span><div><h3>有哪些可选方案</h3><p>保留“不改变计划”和“补充数据”的低干预选项。</p></div></div>
          {decisionCase.options.map(row=><label className="aic-option" key={row.id}><input type="radio" name={`option-${decisionCase.id}`} checked={selectedOptionId===row.id} onChange={()=>setSelectedOptionId(row.id)}/><span><b>{row.label}</b><small>{row.rationale}</small></span><i className="aic-pill">{row.actionKind?'可形成草案':'人工决定'}</i></label>)}
          {error&&<div className="aic-error">{error}</div>}
          <div className="aic-case-actions"><button className="aic-btn" onClick={()=>onNavigate?.('knowledge')}>查看知识库</button><button className="aic-btn primary" disabled={!option?.actionKind||busy} onClick={formProposal}>{busy?'准备中…':option?.actionKind?'形成所选草案':'此选项无需写入'}</button></div>
        </section>
      </div>
      <aside className="aic-side">
        <section className="aic-side-card"><h3>分析范围</h3><p>本次生成保留范围快照。</p><div className="aic-scope"><div><span>运动员</span><b>{decisionCase.scope.athlete.name}</b></div><div><span>指标</span><b>{decisionCase.scope.metric.label}</b></div><div><span>观察窗口</span><b>{decisionCase.scope.filters.fromDate||'最早'} — {decisionCase.scope.filters.toDate||'最新'}</b></div><div><span>知识范围</span><b>{decisionCase.snapshot.knowledgeScopes.join(' + ')}</b></div></div></section>
        <section className="aic-side-card"><h3>证据充分性</h3><p>不是 AI 置信度。</p><div className="aic-quality">纵向基线：{decisionCase.evidenceSufficiency.metricBaseline}<br/>训练负荷：{decisionCase.evidenceSufficiency.trainingLoad}<br/>知识：{decisionCase.evidenceSufficiency.knowledge}<br/>有效样本：{summary.validCount||0}</div></section>
        <section className="aic-side-card"><h3>生成记录</h3><p>只读、可复跑、可审计。</p><div className="aic-scope"><div><span>案例</span><b>{decisionCase.id}</b></div><div><span>合同</span><b>{decisionCase.snapshot.decisionPolicy}</b></div><div><span>状态</span><b>等待人工决定</b></div></div></section>
      </aside>
    </div>
    {proposal&&<AiActionConfirmation proposal={proposal} actions={decisionTools.actions} onClose={()=>setProposal(null)} onNavigate={onNavigate}/>}
  </>;
}

Object.assign(window, { AiDecisionCaseView, AiActionConfirmation });
