// AppView — The 4 apartados of Cynamonurs.
// Singular plan model: 1 dx, 1 obj, 1 int with strict selection limits.

const { useState: uS, useMemo: uM, useEffect: uE } = React;

// ─── CUENTA ──────────────────────────────────────────────────
// La sección de Cuenta vive ahora en src/Cuenta.jsx (rediseño editorial).
// Aquí solo la referenciamos desde window para no duplicar lógica.
const CuentaSection = (props) =>
  window.CuentaSection ? React.createElement(window.CuentaSection, props) : null;

// ─── CASOS ──────────────────────────────────────────────────
const CasesSection = () => {
  const [q, setQ] = uS('');
  const [filter, setFilter] = uS('all');

  const filtered = uM(() => {
    let list = CASOS;
    if (filter !== 'all') list = list.filter(c => c.status === filter);
    if (q.trim()) {
      const s = q.toLowerCase();
      list = list.filter(c =>
        c.paciente.toLowerCase().includes(s) ||
        c.contexto.toLowerCase().includes(s) ||
        c.rels.some(r => r.label.toLowerCase().includes(s) || r.code.toLowerCase().includes(s))
      );
    }
    return list;
  }, [q, filter]);

  const kindMeta = {
    dx: { dot: 'var(--wine-500)', code: 'Dx' },
    ob: { dot: 'var(--sage-500)', code: 'Obj' },
    iv: { dot: 'var(--blue-500)', code: 'Int' },
  };

  return (
    <div className="fade-in" data-screen-label="App — Casos">
      <div className="case-bar">
        <div className="searchbar-web">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
          <input placeholder="Buscar por paciente, código o diagnóstico…" value={q} onChange={(e) => setQ(e.target.value)}/>
        </div>
        <div className="tools-tabs" style={{ margin: 0 }}>
          {[['all', 'Todos'], ['active', 'Activos'], ['draft', 'Borradores'], ['archived', 'Archivados']].map(([k, l]) => (
            <button key={k} className={'tools-chip ' + (filter === k ? 'on' : '')} onClick={() => setFilter(k)}>{l}</button>
          ))}
        </div>
        <button className="btn-primary" style={{ padding: '12px 18px' }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
          Nuevo caso
        </button>
      </div>

      {filtered.length === 0 ? (
        <div className="empty">
          <img src={MASCOT} alt=""/>
          <h4>Sin resultados</h4>
          <p>No encontramos casos con ese criterio. Prueba con otra palabra.</p>
        </div>
      ) : (
        <div className="cases-grid">
          {filtered.map(c => (
            <div key={c.id} className="case-card">
              <div className="case-head">
                <div>
                  <h4 className="case-patient">{c.paciente}</h4>
                  <div className="case-meta">{c.contexto}</div>
                </div>
                <span className={'case-status ' + (c.status === 'active' ? '' : c.status)}>{c.statusLabel}</span>
              </div>
              <div className="case-rels">
                {c.rels.map((r, i) => (
                  <div key={i} className={'case-rel ' + r.kind}>
                    <span className="dotty" style={{ background: kindMeta[r.kind].dot }}/>
                    <span className="code">{kindMeta[r.kind].code} · {r.code}</span>
                    <span className="lbl">{r.label}</span>
                  </div>
                ))}
              </div>
              <div className="case-foot">
                <span>Actualizado · {c.actualizado}</span>
                <span style={{ color: 'var(--cinnamon-500)', fontWeight: 700 }}>Abrir →</span>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

// ─── Smart search (priority + match context) ────────────────
function smartSearch(items, q, kind) {
  if (!q.trim()) return items.map(it => ({ item: it, where: null, score: 0 }));
  const tokens = q.toLowerCase().split(/\s+/).filter(t => t.length > 0);

  const fields = kind === 'dx'
    ? [['etiqueta', 1000, null], ['codigo', 900, null], ['definicion', 200, 'Definición'], ['caracteristicas', 400, 'Características'], ['factores', 400, 'Factores']]
    : kind === 'ob'
    ? [['titulo', 1000, null], ['codigo', 900, null], ['definicion', 200, 'Definición'], ['indicadores', 400, 'Indicadores']]
    : [['nombre', 1000, null], ['codigo', 900, null], ['definicion', 200, 'Definición'], ['actividades', 400, 'Actividades']];

  const matches = [];
  for (const it of items) {
    let score = 0;
    let bestNonTitleField = null;
    let matchedSnippet = null;

    for (const [field, weight, label] of fields) {
      const val = it[field];
      if (val == null) continue;
      if (Array.isArray(val)) {
        for (const v of val) {
          const txt = (typeof v === 'string' ? v : v.descripcion || '').toLowerCase();
          if (tokens.every(t => txt.includes(t))) {
            score += weight;
            if (label && !bestNonTitleField) {
              bestNonTitleField = label;
              matchedSnippet = typeof v === 'string' ? v : v.descripcion;
            }
            break;
          }
        }
      } else {
        const txt = String(val).toLowerCase();
        if (tokens.every(t => txt.includes(t))) {
          score += weight;
          if (label && !bestNonTitleField) {
            bestNonTitleField = label;
            matchedSnippet = val.length > 80 ? val.slice(0, 80) + '…' : val;
          }
        }
      }
    }

    if (score > 0) {
      matches.push({ item: it, where: bestNonTitleField, snippet: matchedSnippet, score });
    }
  }
  matches.sort((a, b) => b.score - a.score);
  return matches;
}

// ─── DxSection ──────────────────────────────────────────────
const DxSection = ({ onOpenFinal }) => {
  const [kind, setKind] = uS('dx');
  const [q, setQ] = uS('');
  const [domain, setDomain] = uS('all');
  const [selected, setSelected] = uS(null);
  const [onlySuggested, setOnlySuggested] = uS(false);
  const [plan] = PlanStore.use();
  const detailRef = React.useRef(null);

  // Scroll the detail into view whenever the user picks a new card.
  uE(() => {
    if (!selected) return;
    const t = setTimeout(() => {
      const el = detailRef.current;
      if (!el) return;
      const y = el.getBoundingClientRect().top + window.scrollY - 80;
      window.scrollTo({ top: y, behavior: 'instant' });
    }, 80);
    return () => clearTimeout(t);
  }, [selected?.codigo]);

  const ds = window.DATA;
  if (!ds?.loaded) {
    return (
      <div className="empty fade-in"><img src={MASCOT} alt=""/><h4>Preparando tu biblioteca…</h4><p>Un momento, estamos terminando de indexar.</p></div>
    );
  }

  // Allow detail components to advance to the next stage.
  const goToKind = (next) => {
    setKind(next);
    setSelected(null);
    // Scroll to the top of the dx-section so the user lands on the new tab cleanly.
    const layoutEl = document.querySelector('.dx-segmented');
    if (layoutEl) {
      const y = layoutEl.getBoundingClientRect().top + window.scrollY - 80;
      window.scrollTo({ top: y, behavior: 'instant' });
    }
  };

  const source = kind === 'dx' ? ds.dxs : kind === 'ob' ? ds.objs : ds.ints;

  // Suggested codes from the current diagnostic
  const suggestedSet = uM(() => {
    if (!plan.dx) return null;
    if (kind === 'ob') {
      const list = ds.relations?.objByDx?.[plan.dx.codigo] || [];
      return new Map(list.map(({ code, score }) => [code, score]));
    }
    if (kind === 'iv') {
      const list = ds.relations?.intByDx?.[plan.dx.codigo] || [];
      return new Map(list.map(({ code, score }) => [code, score]));
    }
    return null;
  }, [plan.dx, kind, ds.relations]);

  // Reset filters/selection when the user switches segment (Dx → Obj → Int).
  uE(() => {
    setSelected(null);
    setDomain('all');
    setQ('');
  }, [kind]);

  // Auto-enable "Sugeridos" when the current dx changes or kind changes.
  // IMPORTANTE: solo se activa si el diagnóstico TIENE relaciones guardadas.
  // Un diagnóstico nuevo (todavía sin entrada en relations.json) muestra la
  // lista completa en vez de una lista vacía. Así, al actualizar el libro de
  // diagnósticos en el futuro, los Dx nuevos siguen siendo usables sin romper nada.
  uE(() => {
    if ((kind === 'ob' || kind === 'iv') && plan.dx) {
      setOnlySuggested(!!(suggestedSet && suggestedSet.size > 0));
    } else {
      setOnlySuggested(false);
    }
  }, [kind, plan.dx?.codigo, suggestedSet]);

  const filtered = uM(() => {
    let list = source.items;
    if (onlySuggested && suggestedSet) {
      list = list.filter(it => suggestedSet.has(it.codigo));
      // Sort by suggestion score
      list = [...list].sort((a, b) => (suggestedSet.get(b.codigo) || 0) - (suggestedSet.get(a.codigo) || 0));
    }
    if (domain !== 'all') list = list.filter(it => String(it.dominio_num) === String(domain));

    // Objetivos/Intervenciones sin búsqueda: ordenar por dominio → clase → código
    if ((kind === 'ob' || kind === 'iv') && !q.trim() && !onlySuggested) {
      list = [...list].sort((a, b) => {
        const dn = (Number(a.dominio_num) || 0) - (Number(b.dominio_num) || 0);
        if (dn !== 0) return dn;
        const ca = String(a.clase_codigo || a.clase || '');
        const cb = String(b.clase_codigo || b.clase || '');
        const cc = ca.localeCompare(cb, 'es', { numeric: true });
        if (cc !== 0) return cc;
        return String(a.codigo).localeCompare(String(b.codigo), 'es', { numeric: true });
      });
      return list.slice(0, 400).map(it => ({ item: it, where: null, score: 0 }));
    }

    const ranked = smartSearch(list, q, kind);
    // If suggested mode and no query, preserve suggestion order
    if (onlySuggested && !q.trim() && suggestedSet) {
      return list.slice(0, 200).map(it => ({ item: it, where: null, score: suggestedSet.get(it.codigo) || 0 }));
    }
    return ranked.slice(0, 200);
  }, [source, q, domain, kind, onlySuggested, suggestedSet]);

  const domainsList = [
    { num: 'all', name: kind === 'dx' ? 'Todos los dominios' : kind === 'ob' ? 'Todos los dominios' : 'Todos los campos', count: source.items.length },
    ...source.dominios.map(d => ({ num: String(d.num), name: d.name.replace(/^(Dominio|Campo)\s*\d+:\s*/, ''), count: source.items.filter(it => String(it.dominio_num) === String(d.num)).length })),
  ];

  const cssKind = kind === 'dx' ? 'nanda' : kind === 'ob' ? 'noc' : 'nic';
  const getLabel = (it) => it.etiqueta || it.titulo || it.nombre;
  const getMeta = (it) => kind === 'dx' ? it.dominio : (kind === 'ob' ? `${it.escala?.length || 5} niveles · ${it.indicadores?.length || 0} indicadores` : it.dominio);

  const canShowSuggestedToggle = (kind === 'ob' || kind === 'iv') && plan.dx;
  // ¿Este diagnóstico aún no tiene relaciones guardadas? (p. ej. un Dx nuevo
  // agregado al actualizar el libro, antes de regenerar relations.json).
  const noRels = canShowSuggestedToggle && !(suggestedSet && suggestedSet.size > 0);

  // Agrupar por dominio → clase al navegar Objetivos/Intervenciones (sin búsqueda ni modo sugeridos).
  const grouped = (kind === 'ob' || kind === 'iv') && !q.trim() && !onlySuggested;

  const renderCard = ({ item: it, where, snippet }) => (
    <button
      key={it.codigo}
      className={'dx-card ' + cssKind + (selected?.codigo === it.codigo ? ' on' : '')}
      onClick={() => {
        setSelected(it);
        if (kind === 'dx' && plan.dx?.codigo !== it.codigo) setPlanDx(it);
        else if (kind === 'ob' && plan.obj?.codigo !== it.codigo) setPlanObjective(it);
        else if (kind === 'iv' && plan.int?.codigo !== it.codigo) setPlanIntervention(it);
      }}
    >
      <span className="dot"/>
      <div className="dx-card-body">
        <div className="dx-card-code mono">
          {it.codigo}
          {onlySuggested && suggestedSet?.has(it.codigo) && (
            <span className="suggested-pip">★ Sugerido</span>
          )}
        </div>
        <div className="dx-card-title">{getLabel(it)}</div>
        <div className="dx-card-meta">{getMeta(it)}</div>
        {where && (
          <div className="match-badge">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
            También en: <strong>{where}</strong> — "{snippet}"
          </div>
        )}
      </div>
      <span className="chev">›</span>
    </button>
  );

  const renderGroupedList = () => {
    const out = [];
    let curKey = null;
    filtered.forEach((entry) => {
      const it = entry.item;
      const claseTxt = (it.clase || '').replace(/^Clase\s*[\w\d]+:?\s*/i, '');
      const key = (domain === 'all' ? (it.dominio_num + '|') : '') + (it.clase_codigo || it.clase || '—');
      if (key !== curKey) {
        curKey = key;
        out.push(
          <div className="dx-class-subhead" key={'h-' + key}>
            {domain === 'all' && (
              <span className="dx-class-dom">{kind === 'iv' ? 'Campo' : 'Dominio'} {it.dominio_num} · {(it.dominio || '').replace(/^(Campo|Dominio)\s*\d+:?\s*/i, '')}</span>
            )}
            <span className="dx-class-name">
              {it.clase_codigo ? 'Clase ' + it.clase_codigo + ' · ' : ''}{claseTxt || 'Sin clase'}
            </span>
          </div>
        );
      }
      out.push(renderCard(entry));
    });
    return out;
  };

  return (
    <div className="fade-in" data-screen-label="App — Diagnósticos / Objetivos / Intervenciones">
      <div className="dx-segmented">
        <button className={kind === 'dx' ? 'on nanda' : ''} onClick={() => setKind('dx')}>
          ● Diagnósticos <span style={{ opacity: 0.7, marginLeft: 6 }} className="mono">{ds.dxs.items.length}</span>
        </button>
        <button className={kind === 'ob' ? 'on noc' : ''} onClick={() => setKind('ob')}>
          ● Objetivos <span style={{ opacity: 0.7, marginLeft: 6 }} className="mono">{ds.objs.items.length}</span>
        </button>
        <button className={kind === 'iv' ? 'on nic' : ''} onClick={() => setKind('iv')}>
          ● Intervenciones <span style={{ opacity: 0.7, marginLeft: 6 }} className="mono">{ds.ints.items.length}</span>
        </button>
      </div>

      {(() => {
        const ek = kind === 'dx' ? 'nanda' : kind === 'ob' ? 'noc' : 'nic';
        const ed = window.EDITIONS?.[ek];
        if (!ed) return null;
        return (
          <div className={'dx-edition ' + ek}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M6 4h11l4 4v12H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="M16 4v6h6"/></svg>
            <span>Edición soportada: <strong>{ed.edicion}</strong></span>
          </div>
        );
      })()}

      {canShowSuggestedToggle && (
        <div className={'suggested-banner' + (noRels ? ' no-rels' : '')}>
          <div className="suggested-banner-icon">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v2M12 19v2M5 12H3M21 12h-2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/><circle cx="12" cy="12" r="4"/></svg>
          </div>
          <div className="suggested-banner-body">
            <div className="suggested-banner-title">
              {noRels ? 'Aún sin sugerencias para este diagnóstico' : 'Sugerencias para tu diagnóstico'}
            </div>
            <div className="suggested-banner-sub">
              <span className="mono small">{plan.dx.codigo}</span> · {plan.dx.etiqueta}
              {noRels
                ? ` · te mostramos ${kind === 'ob' ? 'todos los objetivos' : 'todas las intervenciones'} para que elijas`
                : `${' · '}${(suggestedSet?.size || 0)} ${kind === 'ob' ? 'objetivos' : 'intervenciones'} sugerid${kind === 'ob' ? 'os' : 'as'} por contenido`}
            </div>
          </div>
          {!noRels && (
            <button
              className={'suggested-toggle ' + (onlySuggested ? 'on' : '')}
              onClick={() => setOnlySuggested(v => !v)}
            >
              {onlySuggested ? '✓ Solo sugeridos' : 'Ver todos'}
            </button>
          )}
        </div>
      )}

      <div className="dx-layout">
        <div className="dx-main">
          {/* Domain / campo filter — horizontal chip row */}
          <div className="dx-filter-row">
            <span className="dx-filter-label">{kind === 'iv' ? 'Campo:' : 'Dominio:'}</span>
            <div className="dx-filter-scroll">
              {domainsList.map(d => (
                <button
                  key={d.num}
                  className={'dx-filter-chip ' + (String(domain) === String(d.num) ? 'on' : '')}
                  onClick={() => setDomain(String(d.num))}
                >
                  <span className={'swatch ' + (d.num === 'all' ? '' : cssKind)}/>
                  <span>{d.name}</span>
                  <span className="pip">{d.count}</span>
                </button>
              ))}
            </div>
          </div>

          <div className="searchbar-web" style={{ marginBottom: 18 }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
            <input placeholder={kind === 'dx' ? 'Buscar un diagnóstico, código o característica…' : kind === 'ob' ? 'Buscar un objetivo, código o indicador…' : 'Buscar una intervención, código o actividad…'} value={q} onChange={e => setQ(e.target.value)}/>
            <span className="mono" style={{ color: 'var(--fg-muted)', fontSize: 12 }}>{filtered.length} / {onlySuggested && suggestedSet ? suggestedSet.size : source.items.length}</span>
          </div>

          <div className="dx-list">
            {grouped ? renderGroupedList() : filtered.map((entry) => renderCard(entry))}
            {filtered.length === 0 && (
              <div className="empty">
                <h4>Sin resultados</h4>
                <p>{onlySuggested
                  ? 'Pulsa “Ver todos” para mostrar la lista completa.'
                  : 'Prueba con otra palabra o quita el filtro de dominio.'}</p>
              </div>
            )}
          </div>

          {selected && (
            <div ref={detailRef}>
              {kind === 'dx' ? <DxDetail item={selected} plan={plan} goToKind={goToKind}/> :
               kind === 'ob' ? <ObjDetail item={selected} plan={plan} goToKind={goToKind}/> :
                               <IntDetail item={selected} plan={plan} goToKind={goToKind}/>}
            </div>
          )}
        </div>

        <PlanSummary
          currentKind={kind}
          onGoToKind={goToKind}
          onOpenFinal={onOpenFinal}
        />
      </div>
    </div>
  );
};

// ─── Detail: Diagnóstico ────────────────────────────────────
function DxDetail({ item, plan, goToKind }) {
  const type = detectDxType(item.etiqueta);
  const inPlan = plan.dx?.codigo === item.codigo;
  const planDx = inPlan ? plan.dx : null;
  const dxReady = inPlan && isDxReady(planDx);

  const isCharSelectable = type === 'real' || type === 'promocion';
  const isFactSelectable = type === 'real' || type === 'riesgo' || type === 'sindrome';

  const charLabel = type === 'promocion' ? 'Signos de deseo de mejora' : 'Características definitorias';
  const factLabel = type === 'riesgo' ? 'Factores de riesgo' : 'Factores relacionados';

  const isSelected = (group, v) => planDx?.[group]?.includes(v);

  return (
    <div className="dx-detail fade-in">
      <div className="dx-detail-head">
        <span className="dx-detail-code">Diagnóstico · {item.codigo}</span>
        {item.dominio && <span className="chip">{item.dominio.replace(/^Dominio\s*\d+:\s*/, '')}</span>}
        {item.clase && <span className="chip">{item.clase.replace(/^Clase\s*\w+:\s*/, '')}</span>}
        <span className="chip" style={{ background: 'var(--wine-50)', color: 'var(--wine-700)' }}>{dxTypeLabel(type)}</span>
      </div>
      <h2>{item.etiqueta}</h2>
      <div className="dx-detail-block">
        <h5>Definición</h5>
        <p>"{item.definicion}"</p>
      </div>

      <div className="dx-detail-block">
        <h5 style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span>Estructura del diagnóstico</span>
          <span className="mono small muted" style={{ fontWeight: 600, textTransform: 'none', letterSpacing: 0 }}>{dxTypeStructure(type)}</span>
        </h5>
      </div>

      {!inPlan && (
        <div style={{ background: 'var(--cream-50)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: 16, marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontWeight: 700, color: 'var(--cinnamon-900)', marginBottom: 2 }}>Selecciona este diagnóstico para tu plan</div>
            <div style={{ fontSize: 13, color: 'var(--cinnamon-700)' }}>Después marca hasta {MAX_CARS} característica(s) y {MAX_FACTORS} factor.</div>
          </div>
          <button className="btn-primary" onClick={() => setPlanDx(item)}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
            Usar para el plan
          </button>
        </div>
      )}

      {item.caracteristicas?.length > 0 && (
        <div className="dx-detail-block">
          <h5>
            {charLabel}
            {isCharSelectable && inPlan && (
              <span style={{ color: 'var(--cinnamon-500)', fontWeight: 700, marginLeft: 8 }}>
                · {planDx.selectedDefinitorias.length}/{MAX_CARS} seleccionada(s)
              </span>
            )}
          </h5>
          <SelectableList
            items={item.caracteristicas}
            selectable={isCharSelectable && inPlan}
            isOn={(v) => isSelected('selectedDefinitorias', v)}
            onToggle={(v) => togglePlanDxItem('selectedDefinitorias', v)}
            atLimit={planDx && planDx.selectedDefinitorias.length >= MAX_CARS}
          />
        </div>
      )}
      {item.factores?.length > 0 && (
        <div className="dx-detail-block">
          <h5>
            {factLabel}
            {isFactSelectable && inPlan && (
              <span style={{ color: 'var(--cinnamon-500)', fontWeight: 700, marginLeft: 8 }}>
                · {planDx.selectedFactores.length}/{MAX_FACTORS} seleccionado
              </span>
            )}
          </h5>
          <SelectableList
            items={item.factores}
            selectable={isFactSelectable && inPlan}
            isOn={(v) => isSelected('selectedFactores', v)}
            onToggle={(v) => togglePlanDxItem('selectedFactores', v)}
            atLimit={planDx && planDx.selectedFactores.length >= MAX_FACTORS}
          />
        </div>
      )}
      {item.poblacion_riesgo?.length > 0 && (
        <div className="dx-detail-block">
          <h5>Población en riesgo <span className="mono small muted" style={{ fontWeight: 600, textTransform: 'none' }}>· solo lectura</span></h5>
          <ul className="info-list">{item.poblacion_riesgo.map((c, i) => <li key={i}>{c}</li>)}</ul>
        </div>
      )}
      {item.condiciones_asociadas?.length > 0 && (
        <div className="dx-detail-block">
          <h5>Condiciones asociadas <span className="mono small muted" style={{ fontWeight: 600, textTransform: 'none' }}>· solo lectura</span></h5>
          <ul className="info-list">{item.condiciones_asociadas.map((c, i) => <li key={i}>{c}</li>)}</ul>
        </div>
      )}

      {inPlan && (
        <div className="dx-detail-block">
          <h5>Manifestaciones <span className="mono small muted" style={{ fontWeight: 600, textTransform: 'none' }}>· tu valoración (texto libre)</span></h5>
          <p className="ind-help">Describe cómo se manifiesta el diagnóstico en tu paciente. Se mostrará en el documento final como "manifestado por…".</p>
          <textarea
            className="manif-input"
            placeholder="Ej.: manifestado por disnea de esfuerzo, saturación de O₂ 89%, uso de músculos accesorios…"
            value={planDx?.manifestaciones || ''}
            onChange={(e) => updatePlanDxManifestaciones(e.target.value)}
            rows={3}
          />
        </div>
      )}

      {inPlan && (
        <div style={{ marginTop: 26, padding: 16, background: 'var(--sage-100)', border: '1px solid var(--sage-300)', borderRadius: 12 }}>
          <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--sage-700)', marginBottom: 6 }}>
            {dxReady ? '✓ Diagnóstico listo' : '○ Faltan selecciones'}
          </div>
          <div style={{ fontSize: 13.5, color: 'var(--cinnamon-800)', lineHeight: 1.55, marginBottom: dxReady ? 14 : 0 }}>
            <strong>Vista previa:</strong> {buildDxSentence(planDx)}
          </div>
          {dxReady && (
            <button className="btn-primary" onClick={() => goToKind?.('ob')} style={{ width: '100%', justifyContent: 'center' }}>
              Continuar a Objetivos
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
            </button>
          )}
        </div>
      )}
    </div>
  );
}

// ─── Detail: Objetivo ───────────────────────────────────────
function ObjDetail({ item, plan, goToKind }) {
  const inPlan = plan.obj?.codigo === item.codigo;
  const planObj = inPlan ? plan.obj : null;
  const atIndLimit = planObj && planObj.selectedIndicadores.length >= MAX_INDICATORS;
  const objReady = inPlan && isObjReady(planObj);

  return (
    <div className="dx-detail fade-in">
      <div className="dx-detail-head">
        <span className="dx-detail-code noc">Objetivo · {item.codigo}</span>
        {item.dominio && <span className="chip">{item.dominio.replace(/^Dominio\s*\d+:\s*/, '')}</span>}
        {item.clase && <span className="chip">{item.clase.replace(/^Clase\s*\w+:\s*/, '')}</span>}
      </div>
      <h2>{item.titulo}</h2>
      <div className="dx-detail-block">
        <h5>Definición</h5>
        <p>"{item.definicion}"</p>
      </div>

      {item.escala?.length > 0 && (
        <div className="dx-detail-block">
          <h5>Escala de medición · <span style={{ fontWeight: 600, color: 'var(--cinnamon-700)', textTransform: 'none', letterSpacing: 0 }}>específica de este objetivo</span></h5>
          <div className="escala-grid">
            {item.escala.map((n, i) => (
              <div key={i} className="escala-pill">
                <span className="escala-num mono">{i + 1}</span>
                <span className="escala-txt">{n}</span>
              </div>
            ))}
          </div>
        </div>
      )}

      {!inPlan ? (
        <div style={{ background: 'var(--cream-50)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: 16, marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontWeight: 700, color: 'var(--cinnamon-900)', marginBottom: 2 }}>Seleccionar este objetivo {plan.obj && <span style={{ color: 'var(--wine-700)', fontWeight: 600, fontSize: 12 }}>· reemplazará el actual ({plan.obj.codigo})</span>}</div>
            <div style={{ fontSize: 13, color: 'var(--cinnamon-700)' }}>Después marca los indicadores y define la puntuación Diana usando esta escala.</div>
          </div>
          <button className="btn-primary" onClick={() => setPlanObjective(item)}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
            Usar como objetivo
          </button>
        </div>
      ) : (
        <>
          <div className="dx-detail-block">
            <h5>Indicadores <span style={{ color: 'var(--cinnamon-500)', fontWeight: 700 }}>· {planObj.selectedIndicadores.length}/{MAX_INDICATORS} seleccionado(s)</span></h5>
            <p className="ind-help">Marca un indicador y debajo define su <strong>escala de medición</strong> individual (puntuación basal → meta).</p>
            <ul className="select-list selectable ind-list">
              {item.indicadores.map((ind) => {
                const on = planObj.selectedIndicadores.includes(ind.codigo);
                const blocked = !on && atIndLimit;
                const sc = (planObj.indScores && planObj.indScores[ind.codigo]) || { basal: 1, meta: item.escala?.length || 5 };
                return (
                  <li key={ind.codigo} className={'ind-item' + (on ? ' on' : '')}>
                    <button
                      className={'select-row ' + (on ? 'on' : '') + (blocked ? ' blocked' : '')}
                      onClick={() => !blocked && togglePlanObjectiveIndicator(ind.codigo)}
                      title={blocked ? 'Alcanzaste el límite. Deselecciona uno primero.' : undefined}
                    >
                      <span className="check">
                        {on && <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7"/></svg>}
                      </span>
                      <span className="mono small" style={{ color: 'var(--cinnamon-500)', minWidth: 56, fontWeight: 700 }}>{ind.codigo}</span>
                      <span>{ind.descripcion}</span>
                    </button>

                    {on && (
                      <div className="ind-scale fade-in">
                        <div className="ind-scale-head">
                          <span className="mono small">{ind.codigo}</span> · Escala de medición de este indicador
                        </div>
                        <div className="ind-scale-grid">
                          <ScaleSelector
                            label="Puntuación basal (mantener)"
                            escala={item.escala}
                            value={sc.basal}
                            onChange={(v) => updatePlanObjectiveIndicator(ind.codigo, { basal: v })}
                          />
                          <ScaleSelector
                            label="Puntuación diana (aumentar a)"
                            escala={item.escala}
                            value={sc.meta}
                            onChange={(v) => updatePlanObjectiveIndicator(ind.codigo, { meta: v })}
                          />
                        </div>
                        <div className="ind-scale-foot">
                          Meta: <strong>{item.escala?.[sc.basal - 1] || sc.basal}</strong>
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ margin: '0 4px', verticalAlign: 'middle' }}><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                          <strong>{item.escala?.[sc.meta - 1] || sc.meta}</strong>
                        </div>
                      </div>
                    )}
                  </li>
                );
              })}
            </ul>
          </div>
          <div style={{ marginTop: 16, padding: 14, background: 'var(--sage-100)', border: '1px solid var(--sage-300)', borderRadius: 12 }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--sage-700)', marginBottom: objReady ? 12 : 0 }}>
              {objReady ? '✓ Objetivo listo' : '○ Marca al menos un indicador'}
            </div>
            {objReady && (
              <button className="btn-primary" onClick={() => goToKind?.('iv')} style={{ width: '100%', justifyContent: 'center', marginBottom: 8 }}>
                Continuar a Intervenciones
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
              </button>
            )}
            <button className="btn-secondary" style={{ marginTop: objReady ? 0 : 10 }} onClick={clearPlanObjective}>Quitar del plan</button>
          </div>
        </>
      )}
    </div>
  );
}

// ─── Detail: Intervención ───────────────────────────────────
function IntDetail({ item, plan }) {
  const inPlan = plan.int?.codigo === item.codigo;
  const planInt = inPlan ? plan.int : null;
  const atLimit = planInt && planInt.selectedActividades.length >= MAX_ACTIVITIES;
  const intReady = inPlan && isIntReady(planInt);
  const dxReady = isDxReady(plan.dx);
  const objReady = isObjReady(plan.obj);
  const canOpenFinal = intReady && dxReady && objReady;

  return (
    <div className="dx-detail fade-in">
      <div className="dx-detail-head">
        <span className="dx-detail-code nic">Intervención · {item.codigo}</span>
        {item.dominio && <span className="chip">{item.dominio.replace(/^(Campo|Dominio)\s*\d+:\s*/, '')}</span>}
        {item.clase && <span className="chip">{item.clase.replace(/^Clase\s*\w+:\s*/, '')}</span>}
      </div>
      <h2>{item.nombre}</h2>
      <div className="dx-detail-block">
        <h5>Definición</h5>
        <p>"{item.definicion}"</p>
      </div>

      {!inPlan ? (
        <div style={{ background: 'var(--cream-50)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: 16, marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14, flexWrap: 'wrap' }}>
          <div>
            <div style={{ fontWeight: 700, color: 'var(--cinnamon-900)', marginBottom: 2 }}>Seleccionar esta intervención {plan.int && <span style={{ color: 'var(--wine-700)', fontWeight: 600, fontSize: 12 }}>· reemplazará la actual ({plan.int.codigo})</span>}</div>
            <div style={{ fontSize: 13, color: 'var(--cinnamon-700)' }}>Después marca hasta {MAX_ACTIVITIES} actividad(es) a aplicar durante el cuidado.</div>
          </div>
          <button className="btn-primary" onClick={() => setPlanIntervention(item)}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
            Usar como intervención
          </button>
        </div>
      ) : (
        <>
          <div className="dx-detail-block">
            <h5>
              Actividades
              <span style={{ color: 'var(--cinnamon-500)', fontWeight: 700, marginLeft: 8 }}>
                · {planInt.selectedActividades.length}/{MAX_ACTIVITIES} seleccionada(s)
              </span>
            </h5>
            <SelectableList
              items={item.actividades}
              selectable={true}
              isOn={(v) => planInt.selectedActividades.includes(v)}
              onToggle={(v) => togglePlanInterventionActivity(v)}
              atLimit={atLimit}
            />
          </div>
          <div style={{ marginTop: 16, padding: 14, background: 'var(--sage-100)', border: '1px solid var(--sage-300)', borderRadius: 12 }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--sage-700)', marginBottom: intReady ? 12 : 0 }}>
              {intReady ? (canOpenFinal ? '✓ Intervención lista · plan completo' : '✓ Intervención lista · faltan otros pasos') : '○ Marca al menos una actividad'}
            </div>
            {intReady && (
              <button
                className="btn-primary"
                onClick={() => canOpenFinal && window.__openFinalTable?.()}
                disabled={!canOpenFinal}
                style={{ width: '100%', justifyContent: 'center', marginBottom: 8, opacity: canOpenFinal ? 1 : 0.55, cursor: canOpenFinal ? 'pointer' : 'not-allowed' }}
              >
                Ver tabla final
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
              </button>
            )}
            <button className="btn-secondary" style={{ marginTop: intReady ? 0 : 10 }} onClick={clearPlanIntervention}>Quitar del plan</button>
          </div>
        </>
      )}
    </div>
  );
}

// ─── Selectable list (checkbox rows) ────────────────────────
function SelectableList({ items, selectable, isOn, onToggle, atLimit }) {
  return (
    <ul className={'select-list ' + (selectable ? 'selectable' : 'readonly')}>
      {items.map((c, i) => {
        const value = typeof c === 'string' ? c : (c.descripcion || c);
        const on = selectable ? isOn(value) : false;
        const blocked = selectable && !on && atLimit;
        return (
          <li key={i}>
            {selectable ? (
              <button
                className={'select-row ' + (on ? 'on' : '') + (blocked ? ' blocked' : '')}
                onClick={() => !blocked && onToggle(value)}
                title={blocked ? 'Alcanzaste el límite. Deselecciona uno primero.' : undefined}
              >
                <span className="check">
                  {on && (
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l4 4L19 7"/></svg>
                  )}
                </span>
                <span>{value}</span>
              </button>
            ) : (
              <div className="select-row readonly">
                <span className="dotsmall"/>
                <span>{value}</span>
              </div>
            )}
          </li>
        );
      })}
    </ul>
  );
}

// ─── Scale selector (uses objective's own scale) ────────────
function ScaleSelector({ label, escala, value, onChange }) {
  return (
    <div className="diana-slider">
      <label>{label}</label>
      <div className="scale-options">
        {(escala || []).map((txt, i) => (
          <button
            key={i}
            className={'scale-option ' + (value === i + 1 ? 'on' : '')}
            onClick={() => onChange(i + 1)}
          >
            <span className="mono scale-option-num">{i + 1}</span>
            <span className="scale-option-txt">{txt}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

// ─── APP ROOT ────────────────────────────────────────────────
const AppView = ({ initialTab = 'dx', onOpenFinal }) => {
  const [tab, setTab] = uS(initialTab);
  uE(() => { setTab(initialTab); }, [initialTab]);
  uE(() => {
    window.__cynaGoTab = (t) => setTab(t);
    return () => { delete window.__cynaGoTab; };
  }, []);

  const counts = window.DATA?.loaded ? {
    dxs: window.DATA.dxs.items.length,
    objs: window.DATA.objs.items.length,
    ints: window.DATA.ints.items.length,
  } : { dxs: 0, objs: 0, ints: 0 };

  const titles = {
    cuenta: { eyebrow: '01 · Cuenta', title: 'Tu cuenta', sub: 'Perfil, suscripción, preferencias y sincronización.' },
    tools:  { eyebrow: '02 · Herramientas', title: 'Herramientas clínicas', sub: 'Calculadoras y escalas listas para tu turno.' },
    casos:  { eyebrow: '03 · Casos', title: 'Tus casos clínicos', sub: 'Pacientes, planes de cuidado y plantillas.' },
    dx:     { eyebrow: '04 · Diagnósticos · Objetivos · Intervenciones', title: 'Explorador clínico', sub: 'Selecciona un diagnóstico, luego la app sugerirá objetivos e intervenciones relacionados.' },
  };
  const t = titles[tab];

  return (
    <div className="app-shell" data-screen-label="App — Shell">
      <div className="container">
        <div className="app-hero">
          <div className="app-hero-eyebrow">{t.eyebrow}</div>
          <h1>{t.title}</h1>
          <p>{t.sub}</p>
          <div className="app-tabs" role="tablist">
            <button role="tab" className={'app-tab ' + (tab === 'cuenta' ? 'on' : '')} onClick={() => setTab('cuenta')}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="3.5"/><path d="M5 20c0-3.3 3.1-6 7-6s7 2.7 7 6"/></svg>
              Cuenta
            </button>
            <button role="tab" className={'app-tab ' + (tab === 'tools' ? 'on' : '')} onClick={() => setTab('tools')}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L3 18l3 3 6.3-6.3a4 4 0 0 0 5.4-5.4l-2.5 2.5-2-2z"/></svg>
              Herramientas
            </button>
            <button role="tab" className={'app-tab ' + (tab === 'casos' ? 'on' : '')} onClick={() => setTab('casos')}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M4 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/><path d="M4 10h16"/><path d="M9 5V3h6v2"/></svg>
              Casos
              <span className="pip">{CASOS.length}</span>
            </button>
            <button role="tab" className={'app-tab ' + (tab === 'dx' ? 'on' : '')} onClick={() => setTab('dx')}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M6 4h11l4 4v12H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="M16 4v6h6"/><path d="M8 14h8M8 18h6"/></svg>
              Diagnósticos · Objetivos · Intervenciones
              <span className="pip">{counts.dxs + counts.objs + counts.ints}</span>
            </button>
          </div>
        </div>

        <div className="app-body">
          {tab === 'cuenta' && <CuentaSection/>}
          {tab === 'tools' && <ToolsSection/>}
          {tab === 'casos' && <CasesSection/>}
          {tab === 'dx' && <DxSection onOpenFinal={onOpenFinal}/>}
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { AppView, CasesSection, DxSection });
