// ============================================================
// Resultado de Exame — Capítulo 2.
// A médica importa o PDF do laudo; o sistema extrai o texto
// (pdf.js) e usa IA (functional medicine) para identificar os
// biomarcadores, seus valores e classificá-los em Ótimo / Normal
// / Atenção, levando em conta idade e gênero do paciente.
// A médica revisa e ajusta. Os valores ficam disponíveis para o
// capítulo "Biomarcadores em foco" puxar automaticamente.
// ============================================================

const RES_STATUS = [
  { value: 'otimo',   label: 'Ótimo',   kind: 'ok'   },
  { value: 'normal',  label: 'Normal',  kind: 'warn' },
  { value: 'atencao', label: 'Atenção', kind: 'risk' },
];
const RES_STATUS_MAP = { otimo: RES_STATUS[0], normal: RES_STATUS[1], atencao: RES_STATUS[2] };

// Tradução local: usa o idioma do plano (window.__planLang).
function RT(key, vars) {
  const lang = (typeof window !== 'undefined' && window.__planLang) || 'pt-BR';
  return (typeof tr === 'function') ? tr(key, lang, vars) : key;
}
function RStatus(value) { return RT('status.' + value); }
function RCount(n) { return RT(n === 1 ? 'res.bioCountOne' : 'res.bioCountMany', { n }); }

// Catalog (same source as Biomarcadores em foco) — used to enrich each
// detected marker with a category when the AI omits it.
const RES_CATALOG = (typeof window !== 'undefined' && Array.isArray(window.BIO_CATALOG) && window.BIO_CATALOG.length)
  ? window.BIO_CATALOG : [];

// Normalize a biomarker name so "Apo B", "apolipoproteína b" etc. match.
function normBioName(s) {
  return (s || '')
    .toLowerCase()
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]+/g, ' ')
    .trim();
}
const _CATALOG_BY_NORM = (() => {
  const m = {};
  RES_CATALOG.forEach(b => { m[normBioName(b.name)] = b; });
  return m;
})();
function catalogCategory(name) {
  const hit = _CATALOG_BY_NORM[normBioName(name)];
  return hit ? hit.category : '';
}

// ============================================================
// PONTO ÚNICO DE INTEGRAÇÃO DA IA
// ------------------------------------------------------------
// Protótipo (este ambiente): usa o ajudante Claude embutido
// (window.claude.complete) em lotes. NÃO use em produção — não há
// chave protegida e só funciona aqui dentro.
//
// Produção (recomendado): suba um backend da B-Life que guarde a
// chave Anthropic NO SERVIDOR (secret manager) e exponha um
// endpoint autenticado. Então defina, antes deste script carregar:
//     window.BLIFE_EXAM_API = '/api/analisar-exame';
// e toda a leitura passa a ir por lá (a chave nunca toca o front).
//
// Contrato do endpoint (o backend implementa):
//   POST {EXAM_API_ENDPOINT}   (cookie de sessão do médico logado)
//   req  body: { text: string, age: string, sex: string }
//   resp body: { biomarkers: [ { name, value, unit, status, ref, category } ] }
//              status ∈ "otimo" | "normal" | "atencao"
//   O backend é quem chama a Anthropic, faz o batching, aplica
//   rate-limit por usuário e registra o uso/custo.
// ============================================================
const EXAM_API_ENDPOINT = (typeof window !== 'undefined' && window.BLIFE_EXAM_API) || '';

function aiAvailable() {
  return !!EXAM_API_ENDPOINT || !!(typeof window !== 'undefined' && window.claude && window.claude.complete);
}

function statusToEnum(s) {
  const st = normBioName(s);
  if (st.includes('otim')) return 'otimo';
  if (st.includes('aten') || st.includes('alto') || st.includes('baix') || st.includes('alter')) return 'atencao';
  return 'normal';
}

// Normalize a marker object (from backend OR embedded model) into our shape.
function normalizeMarker(m) {
  if (!m || !m.name) return null;
  return {
    name: String(m.name).trim(),
    value: (m.value != null ? String(m.value) : '').trim(),
    unit: (m.unit || '').toString().trim(),
    status: statusToEnum(m.status),
    ref: (m.ref || m.faixa || m.faixa_otima || '').toString().trim(),
    category: m.category || catalogCategory(m.name),
  };
}

// Production path: one authenticated POST to the B-Life backend.
async function classifyViaBackend(text, ctx) {
  let res;
  try {
    res = await fetch(EXAM_API_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ text, age: ctx.age || '', sex: ctx.sex || '' }),
    });
  } catch (e) {
    throw new Error('Não foi possível falar com o servidor de análise da B-Life.');
  }
  if (!res.ok) throw new Error('O servidor de análise retornou erro ' + res.status + '.');
  const data = await res.json().catch(() => null);
  const list = Array.isArray(data) ? data : (data && data.biomarkers) || [];
  const seen = new Set();
  const out = [];
  list.forEach(m => {
    const nm = normalizeMarker(m);
    if (!nm) return;
    const key = normBioName(nm.name);
    if (key && !seen.has(key)) { seen.add(key); out.push(nm); }
  });
  return out;
}

// Build an index of the imported exam keyed by normalized name, so other
// chapters can pull the current value + status for a given biomarker.
function buildExamIndex(plan) {
  const res = (plan && plan.chapters && plan.chapters.resultado) || {};
  const list = res.biomarkers || [];
  const idx = {};
  list.forEach(b => { if (b && b.name) idx[normBioName(b.name)] = b; });
  return idx;
}

// Resolve a biomarker name against the imported exam list, tolerant of
// naming differences ("Vitamina D" ↔ "25-OH Vitamina D", "Apo B" ↔
// "Apolipoproteína B"): exact → substring → token-subset.
function resolveExamMarker(name, list) {
  if (!name || !list || !list.length) return null;
  const q = normBioName(name);
  if (!q) return null;
  let hit = list.find(b => normBioName(b.name) === q);
  if (hit) return hit;
  hit = list.find(b => { const n = normBioName(b.name); return n && (n.includes(q) || q.includes(n)); });
  if (hit) return hit;
  const qt = q.split(' ').filter(Boolean);
  hit = list.find(b => {
    const nt = normBioName(b.name).split(' ').filter(Boolean);
    if (!nt.length) return false;
    const short = qt.length <= nt.length ? qt : nt;
    const long  = qt.length <= nt.length ? nt : qt;
    return short.length > 0 && short.every(tk => long.includes(tk));
  });
  return hit || null;
}

// ─── PDF text extraction (pdf.js) ────────────────────────────
async function extractPdfText(file) {
  const lib = window.pdfjsLib;
  if (!lib) throw new Error('Leitor de PDF não carregou. Verifique a conexão e tente novamente.');
  const buf = await file.arrayBuffer();
  const pdf = await lib.getDocument({ data: buf }).promise;
  let out = '';
  for (let p = 1; p <= pdf.numPages; p++) {
    const page = await pdf.getPage(p);
    const content = await page.getTextContent();
    out += content.items.map(i => i.str).join(' ') + '\n';
  }
  return out.replace(/\u00a0/g, ' ').replace(/[ \t]+/g, ' ').trim();
}

// Split long text into chunks at whitespace boundaries so each AI call
// returns a small, parseable batch (output is capped at ~1024 tokens).
function chunkText(text, size = 4200) {
  const chunks = [];
  let i = 0;
  while (i < text.length) {
    let end = Math.min(i + size, text.length);
    if (end < text.length) {
      const sp = text.lastIndexOf(' ', end);
      if (sp > i + size * 0.6) end = sp;
    }
    chunks.push(text.slice(i, end));
    i = end;
  }
  return chunks.length ? chunks : [''];
}

function parseMarkerLines(raw) {
  const out = [];
  (raw || '').split('\n').forEach(line => {
    const t = line.trim().replace(/^[-*•\d.]+\s*/, '');
    if (!t || t.startsWith('```') || !t.includes('|')) return;
    const parts = t.split('|').map(s => s.trim());
    const [name, value, unit, status, ref] = parts;
    if (!name || /^nome$/i.test(name)) return;
    const nm = normalizeMarker({
      name,
      value: (value || '').replace(/[^0-9.,<>\-]/g, '') || value || '',
      unit, status, ref,
    });
    if (nm) out.push(nm);
  });
  return out;
}

// Classify one chunk of lab text with the model. Terse pipe output keeps
// us under the token cap and easy to parse.
async function classifyChunk(chunk, ctx) {
  if (!(window.claude && window.claude.complete)) {
    throw new Error('IA indisponível neste ambiente. Configure o backend (window.BLIFE_EXAM_API), use "Inserir manualmente" ou "Carregar exame de exemplo".');
  }
  const who = [ctx.sex && `sexo ${ctx.sex.toLowerCase()}`, ctx.age && `${ctx.age} anos`].filter(Boolean).join(', ') || 'adulto';
  const prompt =
`Você é médico(a) de medicina funcional (functional medicine). Abaixo está parte do texto de um laudo laboratorial. Extraia TODOS os biomarcadores que tenham um valor numérico de resultado. Para cada um, classifique o status considerando as FAIXAS ÓTIMAS da medicina funcional (mais restritas que as faixas laboratoriais), para um paciente ${who}:
- otimo = dentro da faixa ótima funcional
- normal = dentro da faixa laboratorial de referência, porém fora do ideal funcional
- atencao = fora da faixa / alterado / requer atenção

Responda APENAS com uma linha por biomarcador, exatamente no formato:
nome|valor|unidade|status|faixa_otima

Sem cabeçalho, sem comentários, sem markdown. Use vírgula decimal como no laudo. Se não houver biomarcadores com valor neste trecho, responda "—".

TEXTO DO LAUDO:
"""${chunk}"""`;
  const resp = await window.claude.complete({ messages: [{ role: 'user', content: prompt }] });
  return parseMarkerLines(resp);
}

async function analyzeExam(text, ctx, onProgress) {
  // Produção: um único POST autenticado ao backend da B-Life.
  // Protótipo: ajudante Claude embutido, processado em lotes.
  if (EXAM_API_ENDPOINT) {
    if (onProgress) onProgress(1, 1);
    return classifyViaBackend(text, ctx);
  }
  const chunks = chunkText(text);
  const seen = new Set();
  const all = [];
  for (let i = 0; i < chunks.length; i++) {
    if (onProgress) onProgress(i + 1, chunks.length);
    let rows = [];
    try { rows = await classifyChunk(chunks[i], ctx); }
    catch (e) { if (i === 0) throw e; }
    rows.forEach(r => {
      const key = normBioName(r.name);
      if (key && !seen.has(key)) { seen.add(key); all.push(r); }
    });
  }
  return all;
}

// ─── Sample exam (no AI / no file needed — for demoing the flow) ──
const SAMPLE_EXAM = {
  fileName: 'Laudo_exemplo_Fabrizio.pdf',
  examDate: '18 abr 2026',
  lab: 'Laboratório DASA',
  biomarkers: [
    { name: 'Colesterol Total', category: 'Cardiovascular', value: '182', unit: 'mg/dL', status: 'otimo', ref: '< 200' },
    { name: 'Colesterol HDL', category: 'Cardiovascular', value: '40', unit: 'mg/dL', status: 'atencao', ref: '> 60' },
    { name: 'Colesterol LDL', category: 'Cardiovascular', value: '108', unit: 'mg/dL', status: 'normal', ref: '< 100' },
    { name: 'Triglicerídeos', category: 'Cardiovascular', value: '88', unit: 'mg/dL', status: 'otimo', ref: '< 90' },
    { name: 'Apolipoproteína B', category: 'Cardiovascular', value: '69', unit: 'mg/dL', status: 'atencao', ref: '< 60' },
    { name: 'Homocisteína', category: 'Cardiovascular', value: '10', unit: 'µmol/L', status: 'normal', ref: '7–8' },
    { name: 'PCR Ultrassensível', category: 'Cardiovascular', value: '0.6', unit: 'mg/dL', status: 'normal', ref: '< 0,5' },
    { name: 'Hemoglobina Glicada', category: 'Cardiovascular', value: '5.2', unit: '%', status: 'otimo', ref: '< 5,4' },
    { name: 'Glicose', category: 'Metabólico', value: '88', unit: 'mg/dL', status: 'otimo', ref: '75–90' },
    { name: 'Insulina', category: 'Metabólico', value: '6.1', unit: 'µUI/mL', status: 'otimo', ref: '< 6' },
    { name: 'TSH', category: 'Tireoide', value: '2.8', unit: 'µUI/mL', status: 'normal', ref: '1–2' },
    { name: 'T4 Livre', category: 'Tireoide', value: '1.2', unit: 'ng/dL', status: 'otimo', ref: '1,1–1,5' },
    { name: 'Ferritina', category: 'Energia & Resistência', value: '40', unit: 'ng/mL', status: 'normal', ref: '70–150' },
    { name: 'Hemoglobina', category: 'Energia & Resistência', value: '15.1', unit: 'g/dL', status: 'otimo', ref: '14–15' },
    { name: 'Vitamina B12', category: 'Energia & Resistência', value: '520', unit: 'pg/mL', status: 'otimo', ref: '> 500' },
    { name: '25-OH Vitamina D', category: 'Imunidade', value: '32', unit: 'ng/mL', status: 'atencao', ref: '50–70' },
    { name: 'Zinco', category: 'Imunidade', value: '95', unit: 'µg/dL', status: 'otimo', ref: '90–120' },
    { name: 'Magnésio', category: 'Metabólico', value: '2.1', unit: 'mg/dL', status: 'normal', ref: '2,2–2,5' },
    { name: 'Alanina aminotransferase', category: 'Fígado', value: '22', unit: 'U/L', status: 'otimo', ref: '< 25' },
    { name: 'Gama GT', category: 'Fígado', value: '34', unit: 'U/L', status: 'normal', ref: '< 20' },
    { name: 'Ácido Úrico', category: 'Cardiovascular', value: '5.8', unit: 'mg/dL', status: 'otimo', ref: '3,5–6' },
    { name: 'Cortisol', category: 'Hormonal', value: '18', unit: 'µg/dL', status: 'normal', ref: '10–15' },
  ],
};

// ─── Bio Age card (editor preview) ─────────────────────────────
function BioAgeCard({ bioAge, chronoAge, examDate }) {
  const lang = (typeof window !== 'undefined' && window.__planLang) || 'pt-BR';
  const n = bioAgeNum(bioAge);
  if (!isFinite(n)) return null;
  const phrase = bioAgePhrase(bioAge, chronoAge, lang);
  const display = String(bioAge).trim();
  return (
    <div className="bioage-card">
      <img className="bioage-mol" src="assets/blife-symbol-molecule-cream.svg" alt=""/>
      <div className="bioage-eyebrow">{tr('bioage.label', lang)}</div>
      <div className="bioage-body">
        <div className="bioage-figure">
          <span className="bioage-num">{display}</span>
          <span className="bioage-unit">{tr('bioage.unit', lang)}</span>
        </div>
        <div className="bioage-side">
          {phrase && <div className="bioage-phrase">{phrase}</div>}
          {isFinite(bioAgeNum(chronoAge)) && (
            <div className="bioage-chrono">{tr('bioage.chrono', lang, { n: bioAgeNum(chronoAge) })}</div>
          )}
          {examDate && <div className="bioage-date">{tr('bioage.examDate', lang, { date: examDate })}</div>}
        </div>
      </div>
    </div>
  );
}

// ─── Status summary card (forest, like the "Dados de saúde" card) ──
function ExamScoreCard({ biomarkers, examDate }) {
  const counts = { otimo: 0, normal: 0, atencao: 0 };
  biomarkers.forEach(b => { counts[b.status] = (counts[b.status] || 0) + 1; });
  const total = biomarkers.length;
  return (
    <div className="exam-score">
      <div className="exam-score-eyebrow">
        {examDate ? RT('pdf.res.scoreEyebrowDate', { n: total, date: examDate }) : RT('pdf.res.scoreEyebrow', { n: total })}
      </div>
      <div className="exam-score-cols">
        <div className="scol ok">
          <div className="num">{counts.otimo}</div>
          <div className="lbl"><span className="dot"/> {RStatus('otimo')}</div>
        </div>
        <div className="scol warn">
          <div className="num">{counts.normal}</div>
          <div className="lbl"><span className="dot"/> {RStatus('normal')}</div>
        </div>
        <div className="scol risk">
          <div className="num">{counts.atencao}</div>
          <div className="lbl"><span className="dot"/> {RStatus('atencao')}</div>
        </div>
      </div>
    </div>
  );
}

// One editable row in the imported exam panel.
function ExamMarkerRow({ item, onChange, onRemove, patient }) {
  const profile = patient ? { gender: patient.sex, age: patient.age } : {};
  const desc = (typeof describeRanges === 'function') ? describeRanges(item.name, profile) : null;
  const cat = (desc && desc.category) ? desc.category : (item.category || RT('res.noCategory'));
  let rangeText = '';
  if (desc && desc.optimal !== '—') {
    const parts = [];
    parts.push(RT('res.optimal') + ' ' + desc.optimal);
    if (desc.regular && desc.regular !== '—') parts.push(RStatus('normal') + ' ' + desc.regular);
    if (desc.attention && desc.attention !== '—') parts.push(RStatus('atencao') + ' ' + desc.attention);
    rangeText = parts.join(' · ');
  } else if (item.ref) {
    rangeText = RT('res.optimal') + ' ' + item.ref;
  }
  return (
    <div className="exam-row-edit">
      <div className="exam-row-id">
        <div className="exam-row-nm">{item.name}</div>
        <div className="exam-row-cat">
          {cat}{rangeText ? ' · ' + rangeText : ''}
        </div>
      </div>
      <div className="exam-row-field">
        <label>{fl('Valor')}</label>
        <input className="input" value={item.value || ''} placeholder="—" onChange={e => onChange({ ...item, value: e.target.value })}/>
      </div>
      <div className="exam-row-field">
        <label>{fl('Unidade')}</label>
        <input className="input" value={item.unit || ''} placeholder="mg/dL" onChange={e => onChange({ ...item, unit: e.target.value })}/>
      </div>
      <div className="exam-row-field" style={{ minWidth: 210 }}>
        <label>{fl('Status')}</label>
        <div className="period-tabs bio-status-tabs">
          {RES_STATUS.map(s => (
            <button key={s.value} className={item.status === s.value ? 'active ' + s.kind : ''} onClick={() => onChange({ ...item, status: s.value })}>{RStatus(s.value)}</button>
          ))}
        </div>
      </div>
      <button className="btn ghost xs" onClick={onRemove} title={RT('res.removeBio')}><Ico.X/></button>
    </div>
  );
}

function ResultadoEditor() {
  const { patient } = usePatient();
  const [data, setData] = useChapter('resultado', { fileName: '', examDate: '', lab: '', bioAge: '', comentario: '', biomarkers: [] });
  const biomarkers = data.biomarkers || [];
  const [phase, setPhase] = React.useState('idle');   // idle | analyzing | error
  const [progress, setProgress] = React.useState(null); // {cur,total}
  const [errMsg, setErrMsg] = React.useState('');
  const [filter, setFilter] = React.useState('todos');
  const [dragOver, setDragOver] = React.useState(false);
  const fileRef = React.useRef(null);

  const hasExam = biomarkers.length > 0;

  const setBiomarkers = (next) => setData(d => ({ ...d, biomarkers: typeof next === 'function' ? next(d.biomarkers || []) : next }));

  const runFile = async (file) => {
    if (!file) return;
    if (file.type && file.type !== 'application/pdf' && !/\.pdf$/i.test(file.name)) {
      setErrMsg('Por enquanto só conseguimos ler arquivos PDF. Converta o exame para PDF e tente de novo.');
      setPhase('error');
      return;
    }
    setPhase('analyzing'); setErrMsg(''); setProgress({ cur: 0, total: 1 });
    try {
      const text = await extractPdfText(file);
      if (!text || text.length < 40) {
        throw new Error('Não consegui ler texto deste PDF — talvez seja um exame escaneado (imagem). Tente um PDF com texto selecionável ou insira manualmente.');
      }
      const markers = await analyzeExam(text, { age: patient.age, sex: patient.sex }, (cur, total) => setProgress({ cur, total }));
      if (!markers.length) {
        throw new Error('A IA não encontrou biomarcadores com valor neste PDF. Confira o arquivo ou insira manualmente.');
      }
      setData(d => ({ ...d, fileName: file.name, biomarkers: markers }));
      setPhase('idle');
      blifeToast(`${markers.length} biomarcadores classificados pela IA`);
    } catch (e) {
      setErrMsg(e.message || 'Falha ao analisar o exame.');
      setPhase('error');
    }
  };

  const onPick = (e) => { const f = e.target.files && e.target.files[0]; if (f) runFile(f); e.target.value = ''; };
  const onDrop = (e) => { e.preventDefault(); setDragOver(false); const f = e.dataTransfer.files && e.dataTransfer.files[0]; if (f) runFile(f); };
  const loadSample = () => {
    setData(d => ({ ...d, ...JSON.parse(JSON.stringify(SAMPLE_EXAM)), comentario: d.comentario || '' }));
    setPhase('idle'); setErrMsg('');
    blifeToast('Exame de exemplo carregado');
  };
  const addManual = () => {
    setData(d => ({ ...d, biomarkers: [...(d.biomarkers || []), { name: 'Novo biomarcador', category: '', value: '', unit: '', status: 'normal', ref: '' }] }));
  };
  const clearExam = () => {
    if (window.confirm('Limpar o exame importado e todos os biomarcadores classificados?')) {
      setData(d => ({ ...d, fileName: '', examDate: '', lab: '', biomarkers: [] }));
      setPhase('idle');
    }
  };

  const update = (i, entry) => setBiomarkers(list => list.map((f, j) => j === i ? entry : f));
  const remove = (i) => setBiomarkers(list => list.filter((_, j) => j !== i));

  // Group + filter for display (Atenção first — clinical priority).
  const order = ['atencao', 'normal', 'otimo'];
  const grouped = order
    .map(st => ({ st, items: biomarkers.map((b, i) => ({ b, i })).filter(x => x.b.status === st) }))
    .filter(g => g.items.length && (filter === 'todos' || filter === g.st));

  return (
    <>
      <SectionHeader
        title="Bio Age e Exame"
        sub="Informe a idade biológica calculada e importe o PDF do exame. A IA identifica os biomarcadores e classifica cada um pela medicina funcional, considerando idade e gênero. Você revisa e ajusta."
        chapterId="resultado"
      />

      <SectionCard title={fl('Idade biológica')} right={<span className="muted tiny">{(typeof tr === 'function' ? tr('bioage.editHint', (window.__planLang||'pt-BR')) : '')}</span>}>
        <div className="grid-3" style={{ gap: 12, alignItems: 'end' }}>
          <div className="field">
            <label>{(typeof tr === 'function' ? tr('bioage.editLabel', (window.__planLang||'pt-BR')) : 'Idade biológica calculada')}</label>
            <input className="input" value={data.bioAge || ''} placeholder="31,7" inputMode="decimal"
              onChange={e => setData(d => ({ ...d, bioAge: e.target.value }))}/>
          </div>
          <div className="field">
            <label>{fl('Idade')} <span className="muted tiny" style={{ textTransform: 'none', letterSpacing: 0 }}>{fl('(opcional)')}</span></label>
            <input className="input" value={patient.age || ''} disabled placeholder="—"
              title={RT('res.chronoFromPatient')}/>
          </div>
          <div className="field">
            <label>{fl('Data do laudo')}</label>
            <input className="input" value={data.examDate || ''} placeholder="18 abr 2026"
              onChange={e => setData(d => ({ ...d, examDate: e.target.value }))}/>
          </div>
        </div>
        {isFinite(bioAgeNum(data.bioAge)) && (
          <div style={{ marginTop: 16 }}>
            <BioAgeCard bioAge={data.bioAge} chronoAge={patient.age} examDate={data.examDate}/>
          </div>
        )}
      </SectionCard>

      <div className="spacer-16"/>

      {!hasExam && phase !== 'analyzing' && (
        <SectionCard title={RT('res.importTitle')} right={<span className="muted tiny">{RT('res.importRight')}</span>}>
          <div
            className={'exam-drop' + (dragOver ? ' over' : '')}
            onClick={() => fileRef.current && fileRef.current.click()}
            onDragOver={e => { e.preventDefault(); setDragOver(true); }}
            onDragLeave={() => setDragOver(false)}
            onDrop={onDrop}
          >
            <div className="exam-drop-ic"><Ico.Upload/></div>
            <div className="exam-drop-ttl">{RT('res.dropTitle')}</div>
            <div className="exam-drop-sub">{RT('res.dropSub')}</div>
            <input ref={fileRef} type="file" accept="application/pdf,.pdf" style={{ display: 'none' }} onChange={onPick}/>
          </div>

          {phase === 'error' && (
            <div className="banner" style={{ background: 'var(--risk-bg)', color: 'var(--risk-ink)', marginTop: 14 }}>
              <Ico.Warn/> <span>{errMsg}</span>
            </div>
          )}

          {!aiAvailable() && (
            <div className="muted tiny" style={{ marginTop: 12 }}>
              A leitura automática por IA roda no ambiente B-Life (ou no backend configurado). Importe um PDF com texto selecionável para classificar os biomarcadores.
            </div>
          )}
        </SectionCard>
      )}

      {phase === 'analyzing' && (
        <SectionCard title={RT('res.analyzingTitle')}>
          <div className="exam-analyzing">
            <div className="exam-analyzing-ic"><Ico.Spinner/></div>
            <div>
              <div className="exam-analyzing-ttl">{RT('res.analyzingMsg')}</div>
              <div className="muted tiny" style={{ marginTop: 4 }}>
                {RT('res.fmPrefix')} {patient.sex || RT('res.sexUnknown')}{patient.age ? `, ${RT('bioage.yearsMany', { n: patient.age })}` : ''}
                {progress && progress.total > 1 ? ` · ${RT('res.chunk', { cur: progress.cur, total: progress.total })}` : ''}
              </div>
            </div>
          </div>
        </SectionCard>
      )}

      {hasExam && phase !== 'analyzing' && (
        <>
          <ExamScoreCard biomarkers={biomarkers} examDate={data.examDate}/>

          <div className="spacer-16"/>

          <SectionCard
            title={RT('res.examImported')}
            right={
              <div style={{ display: 'flex', gap: 8 }}>
                <button className="btn ghost xs" onClick={() => fileRef.current && fileRef.current.click()} title={RT('res.reimportTitle')}><Ico.Refresh/> {RT('res.reimport')}</button>
                <button className="btn danger sm" onClick={clearExam} title={RT('res.clearTitle')}><Ico.Trash/></button>
                <input ref={fileRef} type="file" accept="application/pdf,.pdf" style={{ display: 'none' }} onChange={onPick}/>
              </div>
            }
          >
            <div className="grid-3" style={{ gap: 12, marginBottom: 14 }}>
              <div className="field"><label>{RT('res.file')}</label><input className="input" value={data.fileName || ''} placeholder="exame.pdf" onChange={e => setData({ ...data, fileName: e.target.value })}/></div>
              <div className="field"><label>{fl('Data do laudo')}</label><input className="input" value={data.examDate || ''} placeholder="18 abr 2026" onChange={e => setData({ ...data, examDate: e.target.value })}/></div>
              <div className="field"><label>{RT('res.lab')}</label><input className="input" value={data.lab || ''} placeholder={RT('res.lab')} onChange={e => setData({ ...data, lab: e.target.value })}/></div>
            </div>

            <div className="period-tabs" style={{ marginBottom: 14 }}>
              {[['todos', `${RT('res.all')} · ${biomarkers.length}`], ...RES_STATUS.map(s => [s.value, `${RStatus(s.value)} · ${biomarkers.filter(b => b.status === s.value).length}`])].map(([v, lbl]) => (
                <button key={v} className={filter === v ? 'active' : ''} onClick={() => setFilter(v)}>{lbl}</button>
              ))}
            </div>

            {grouped.map(g => (
              <div key={g.st} className="exam-group">
                <div className="exam-group-head">
                  <span className={'status ' + RES_STATUS_MAP[g.st].kind}><span className="d"/> {RStatus(g.st)}</span>
                  <span className="muted tiny">{RCount(g.items.length)}</span>
                </div>
                <div className="exam-edit-list">
                  {g.items.map(({ b, i }) => (
                    <ExamMarkerRow key={i} item={b} onChange={(e) => update(i, e)} onRemove={() => remove(i)} patient={patient}/>
                  ))}
                </div>
              </div>
            ))}

            <div className="add-section" style={{ padding: 12, marginTop: 14 }} onClick={addManual}>
              <Ico.Plus/> {RT('res.addManual')}
            </div>
          </SectionCard>
        </>
      )}
    </>
  );
}

Object.assign(window, { ResultadoEditor, normBioName, buildExamIndex, resolveExamMarker, RES_STATUS, RES_STATUS_MAP });
