// Libertas Tracker · presentación React. Datos, configuración y cálculos viven
// en módulos JS independientes para permitir una futura API sin rehacer la UI.
;(function () {
const { useEffect, useMemo, useRef, useState } = React;
const { CRITERIA, LEVELS, STATUS_GROUPS, CONFIDENCE } = window.LibertasConfig;
const Logic = window.LibertasLogic;

const EMPTY_FILTERS = { search: '', year: '', status: '', type: '', area: '', verdict: '', body: '' };

function unique(records, getter) {
  return [...new Set(records.map(getter).filter(Boolean))].sort((a, b) => a.localeCompare(b, 'es'));
}

function Dialog({ title, eyebrow, onClose, children, wide = false }) {
  const closeRef = useRef(null);
  const previousFocus = useRef(document.activeElement);
  useEffect(() => {
    closeRef.current?.focus();
    const onKey = (event) => { if (event.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.classList.add('libertas-modal-open');
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.classList.remove('libertas-modal-open');
      previousFocus.current?.focus?.();
    };
  }, [onClose]);
  return (
    <div className="libertas-dialog-backdrop" role="presentation" onMouseDown={(event) => { if (event.target === event.currentTarget) onClose(); }}>
      <section className={`libertas-dialog${wide ? ' is-wide' : ''}`} role="dialog" aria-modal="true" aria-labelledby="libertas-dialog-title">
        <header className="libertas-dialog-head">
          <div>{eyebrow && <div className="libertas-dialog-eyebrow">{eyebrow}</div>}<h2 id="libertas-dialog-title">{title}</h2></div>
          <button ref={closeRef} className="libertas-icon-button" onClick={onClose} aria-label="Cerrar panel">×</button>
        </header>
        <div className="libertas-dialog-body">{children}</div>
      </section>
    </div>
  );
}

function RatingBadge({ score, compact = false }) {
  const rating = Logic.getRating(score);
  const content = <><span className="libertas-rating-symbol" aria-hidden="true">{rating.symbol}</span><span>{compact ? rating.short : rating.label}</span></>;
  const props = { className: `libertas-rating ${Logic.getRatingClass(score)}${compact ? ' is-compact' : ''}`, title: `${rating.label}: ${rating.meaning}`, 'aria-label': `${rating.label}. ${rating.meaning}` };
  return <span {...props}>{content}</span>;
}

function CriterionButton({ law, criterion, onOpen, compact = false, testId }) {
  const evaluation = law.criteria[criterion.id];
  const rating = Logic.getRating(evaluation.score);
  return <button type="button" className="libertas-rating-trigger" data-testid={testId} onClick={() => onOpen(law, criterion.id)} aria-label={`Abrir ficha detallada y desplegar ${criterion.label}: ${rating.label}`} title={`Abrir la ficha detallada en ${criterion.label}`}><RatingBadge score={evaluation.score} compact={compact} /></button>;
}

function AntiLibertasWarning({ law }) {
  if (!law.hasAntiLibertasWarning) return null;
  const names = law.antiCriteria.map((criterion) => criterion.label).join(', ');
  return <div className="libertas-warning" role="note"><span aria-hidden="true">!</span><span>Alerta Anti Libertas en {names}.</span></div>;
}

function EvaluationFreshness({ law }) {
  if (!Logic.isEvaluationOutdated(law)) return null;
  return <div className="libertas-stale" role="note"><span aria-hidden="true">↻</span><span>Revisión potencialmente desactualizada: comprueba si existe una versión o estado legislativo posterior.</span></div>;
}

function OverallVerdict({ law, compact = false }) {
  return <div className="libertas-overall"><RatingBadge score={law.overallVerdict} compact={compact} /><span className="libertas-score" title="Intensidad media del bloque mayoritario, sin contar los criterios Statu Quo">{law.overallScore > 0 ? '+' : ''}{law.overallScore.toFixed(2)}</span>{!compact && <AntiLibertasWarning law={law} />}</div>;
}

function SourceList({ sources = [] }) {
  if (!sources.length) return <p className="libertas-muted">Sin fuentes enlazadas en este ejemplo.</p>;
  return <ul className="libertas-sources">{sources.map((source, index) => <li key={`${source.url}-${index}`}><span>{source.sourceType}</span><a href={source.url} target="_blank" rel="noopener noreferrer">{source.label} <span aria-hidden="true">↗</span></a></li>)}</ul>;
}

function DetailBlock({ title, children }) { return <section className="libertas-detail-block"><h3>{title}</h3>{children}</section>; }
function DetailList({ title, items = [], positive = false, neutral = false }) {
  return <section className={`libertas-detail-block libertas-list-block${positive ? ' is-positive' : ''}${neutral ? ' is-neutral' : ''}`}><h3>{title}</h3>{items.length ? <ul>{items.map((item, index) => <li key={index}>{item}</li>)}</ul> : <p className="libertas-muted">Ningún efecto relevante identificado.</p>}</section>;
}

function TrackerIntroduction({ updatedAt, onMethodology }) {
  return <header className="libertas-intro">
    <span className="libertas-kicker">herramienta · lo que nos imponen · legislación · España · 2026</span>
    <h1>Lo que nos <mark>imponen</mark>. Examina las leyes.</h1>
    <p>Seguimiento de las iniciativas legislativas españolas y de su efecto sobre la autonomía individual, la libertad económica, la propiedad, la fiscalidad y el poder coercitivo del Estado.</p>
    <div className="libertas-intro-actions"><span>Actualizado · {Logic.formatDate(updatedAt)}</span><button className="libertas-primary-button" onClick={onMethodology}>Consultar metodología</button></div>
    <p className="libertas-ai-note"><strong>Procesamiento asistido por IA.</strong> La IA ayuda a localizar, resumir y clasificar los textos. Las fuentes oficiales enlazadas son la referencia y las evaluaciones pueden requerir revisión humana.</p>
  </header>;
}

function SelectFilter({ label, value, onChange, options }) {
  return <label className="libertas-filter"><span>{label}</span><select value={value} onChange={(event) => onChange(event.target.value)}><option value="">Todos</option>{options.map((option) => { const value = typeof option === 'string' ? option : option.value; const text = typeof option === 'string' ? option : option.label; return <option value={value} key={value}>{text}</option>; })}</select></label>;
}

function TrackerFilters({ records, filters, setFilters, resultCount }) {
  const set = (key, value) => setFilters((current) => ({ ...current, [key]: value }));
  const years = unique(records, (law) => Logic.getRelevantDate(law).value?.slice(0, 4)).reverse();
  return <section className="libertas-filter-panel" aria-label="Filtros de iniciativas">
    <div className="libertas-search-row"><label className="libertas-search"><span>Buscar</span><input type="search" value={filters.search} onChange={(event) => set('search', event.target.value)} placeholder="Título, número o palabra clave" /></label><div className="libertas-result-count" aria-live="polite"><strong>{resultCount}</strong> {resultCount === 1 ? 'resultado' : 'resultados'}</div></div>
    <div className="libertas-filter-grid">
      <SelectFilter label="Año" value={filters.year} onChange={(value) => set('year', value)} options={years} />
      <SelectFilter label="Estado" value={filters.status} onChange={(value) => set('status', value)} options={Object.entries(STATUS_GROUPS).map(([value, group]) => ({ value, label: group.label }))} />
      <SelectFilter label="Tipo" value={filters.type} onChange={(value) => set('type', value)} options={unique(records, (law) => law.initiativeType)} />
      <SelectFilter label="Área" value={filters.area} onChange={(value) => set('area', value)} options={unique(records, (law) => law.thematicArea)} />
      <SelectFilter label="Veredicto" value={filters.verdict} onChange={(value) => set('verdict', value)} options={[2, 1, 0, -1, -2].map((value) => ({ value: String(value), label: Logic.getRatingLabel(value) }))} />
      <SelectFilter label="Origen" value={filters.body} onChange={(value) => set('body', value)} options={unique(records, (law) => law.proposingBody)} />
      <button className="libertas-reset-button" onClick={() => setFilters({ ...EMPTY_FILTERS })}>Restablecer filtros</button>
    </div>
  </section>;
}

function SortButton({ label, sortKey, sort, onSort }) {
  const active = sort.key === sortKey;
  return <button className={`libertas-sort${active ? ' is-active' : ''}`} onClick={() => onSort(sortKey)} aria-label={`Ordenar por ${label}`} aria-pressed={active}>{label}<span aria-hidden="true">{active ? (sort.direction === 'asc' ? ' ↑' : ' ↓') : ' ↕'}</span></button>;
}

function LawTable({ records, sort, onSort, onDetail }) {
  return <div className="libertas-table-wrap"><table className="libertas-table"><caption className="sr-only">Comparación liberal-libertaria de iniciativas legislativas</caption><thead><tr>
    <th scope="col">Iniciativa</th><th scope="col">Estado</th><th scope="col"><SortButton label="Fecha" sortKey="date" sort={sort} onSort={onSort} /></th>
    {CRITERIA.map((criterion) => <th scope="col" key={criterion.id}><SortButton label={criterion.short} sortKey={criterion.id} sort={sort} onSort={onSort} /></th>)}
    <th scope="col" className="libertas-verdict-column"><SortButton label="Veredicto final" sortKey="overall" sort={sort} onSort={onSort} /></th>
  </tr></thead><tbody>{records.map((law) => <LawTableRow key={law.id} law={law} onDetail={onDetail} />)}</tbody></table></div>;
}

function LawTableRow({ law, onDetail }) {
  const date = Logic.getRelevantDate(law);
  return <tr><th scope="row"><button className="libertas-law-link" onClick={() => onDetail(law)}>{law.shortTitle}</button><span>{law.officialNumber}</span></th><td><span className={`libertas-status is-${law.simplifiedStatus}`}>{law.status}</span></td><td><time dateTime={date.value || undefined} title={date.label}>{Logic.formatDate(date.value)}</time></td>
    {CRITERIA.map((criterion) => <td key={criterion.id}><CriterionButton law={law} criterion={criterion} compact testId={`table-${law.id}-${criterion.id}`} onOpen={onDetail} /></td>)}
    <td className="libertas-verdict-column"><OverallVerdict law={law} compact />{law.hasAntiLibertasWarning && <span className="libertas-alert-dot" title="Contiene al menos un criterio Anti Libertas" aria-label="Alerta: contiene al menos un criterio Anti Libertas">!</span>}</td></tr>;
}

function LawCard({ law, onDetail }) {
  const date = Logic.getRelevantDate(law);
  return <article className="libertas-law-card"><div className="libertas-card-head"><div><span className={`libertas-status is-${law.simplifiedStatus}`}>{law.status}</span><button className="libertas-law-link" onClick={() => onDetail(law)}>{law.shortTitle}</button><span className="libertas-law-number">{law.officialNumber}</span></div><OverallVerdict law={law} compact /></div><time dateTime={date.value || undefined} title={date.label}>{date.label}: {Logic.formatDate(date.value)}</time><div className="libertas-card-ratings">{CRITERIA.map((criterion) => <div key={criterion.id}><span>{criterion.short}</span><CriterionButton law={law} criterion={criterion} compact testId={`card-${law.id}-${criterion.id}`} onOpen={onDetail} /></div>)}</div>{law.hasAntiLibertasWarning && <AntiLibertasWarning law={law} />}<button className="libertas-card-detail" onClick={() => onDetail(law)}>Ver análisis completo</button></article>;
}

function CriterionAccordion({ law, initialCriterionId = null }) {
  const [expandedId, setExpandedId] = useState(initialCriterionId);
  return <div className="libertas-criterion-accordion">{CRITERIA.map((criterion) => {
    const evaluation = law.criteria[criterion.id];
    const confidence = CONFIDENCE[evaluation.confidence];
    const expanded = expandedId === criterion.id;
    const buttonId = `libertas-criterion-button-${law.id}-${criterion.id}`;
    const panelId = `libertas-criterion-panel-${law.id}-${criterion.id}`;
    return <section className={`libertas-criterion-item${expanded ? ' is-expanded' : ''}`} key={criterion.id}>
      <button id={buttonId} type="button" className="libertas-criterion-toggle" aria-expanded={expanded} aria-controls={panelId} onClick={() => setExpandedId(expanded ? null : criterion.id)}>
        <span>{criterion.label}</span><span className="libertas-criterion-toggle-end"><RatingBadge score={evaluation.score} /><span className="libertas-criterion-chevron" aria-hidden="true">⌄</span></span>
      </button>
      {expanded && <div id={panelId} className="libertas-criterion-panel" role="region" aria-labelledby={buttonId}>
        <div className="libertas-dialog-summary"><span className="libertas-confidence">Confianza {confidence.label}</span></div>
        <p className="libertas-confidence-note">{confidence.description}</p>
        <DetailBlock title="Resumen"><p>{evaluation.summary}</p></DetailBlock>
        <div className="libertas-procon">
          <DetailList title="A favor de la libertad" items={evaluation.proLibertyArguments} positive />
          <DetailList title="En contra de la libertad" items={evaluation.antiLibertyArguments} />
        </div>
        <DetailBlock title="Efecto neto"><p>{evaluation.netAssessment}</p></DetailBlock>
        <DetailList title="Artículos o disposiciones relevantes" items={evaluation.relevantArticles} neutral />
        <DetailBlock title="Fuentes oficiales"><SourceList sources={evaluation.sources} /></DetailBlock>
      </div>}
    </section>;
  })}</div>;
}

function LawDetail({ law, initialCriterionId, onClose }) {
  const dateRows = Object.entries(law.dates || {});
  return <Dialog title={law.shortTitle} eyebrow="Ficha detallada · fuente oficial" onClose={onClose} wide>
    <p className="libertas-full-title">{law.fullTitle}</p><OverallVerdict law={law} /><EvaluationFreshness law={law} />
    <dl className="libertas-metadata"><Meta label="Número oficial" value={law.officialNumber} /><Meta label="Referencia parlamentaria" value={law.parliamentaryReference} /><Meta label="Tipo" value={law.initiativeType} /><Meta label="Estado exacto" value={law.status} /><Meta label="Estado agrupado" value={STATUS_GROUPS[law.simplifiedStatus]?.label} /><Meta label="Institución o grupo" value={law.proposingBody} /><Meta label="Área temática" value={law.thematicArea} /><Meta label="Confianza general" value={CONFIDENCE[law.overallConfidence]?.label} /></dl>
    <DetailBlock title="Resumen neutral"><p>{law.neutralSummary}</p></DetailBlock>
    <div className="libertas-version"><strong>Versión evaluada:</strong> {law.evaluatedVersion}{law.evaluatedVersionDate ? ` · ${Logic.formatDate(law.evaluatedVersionDate)}` : ''}<span>La puntuación corresponde únicamente a esta versión, no a textos anteriores o posteriores.</span></div>
    <DetailBlock title="Cinco evaluaciones"><CriterionAccordion law={law} initialCriterionId={initialCriterionId} /></DetailBlock>
    <DetailBlock title="Fechas"><dl className="libertas-date-list">{dateRows.map(([key, value]) => <Meta key={key} label={Logic.getRelevantDate({ ...law, status: law.status, dates: { [key]: value } }).label === 'Sin fecha' ? key : ({ presented:'Presentación', admitted:'Admisión', congressApproved:'Aprobación Congreso', senateApproved:'Aprobación Senado', finallyApproved:'Aprobación definitiva', published:'Publicación BOE', effective:'Entrada en vigor', rejected:'Rechazo', withdrawn:'Retirada', repealed:'Derogación' }[key] || key)} value={Logic.formatDate(value)} />)}</dl></DetailBlock>
    <DetailBlock title="Palabras clave"><div className="libertas-tags">{law.keywords.map((keyword) => <span key={keyword}>{keyword}</span>)}</div></DetailBlock>
    <DetailBlock title="Fuentes oficiales"><SourceList sources={law.sources} /></DetailBlock>
    <DetailBlock title="Historial legislativo"><ol className="libertas-history">{(law.statusHistory || []).map((item, index) => <li key={index}><time>{Logic.formatDate(item.date)}</time><strong>{item.status}</strong>{item.description && <span>{item.description}</span>}</li>)}</ol></DetailBlock>
    <DetailBlock title="Historial de la evaluación"><ol className="libertas-history">{(law.evaluationHistory || []).map((item, index) => <li key={index}><time>{Logic.formatDate(item.evaluatedAt)}</time><strong>{item.evaluatedVersion}</strong><span>{item.changeReason} · Nuevo índice mayoritario: {item.newOverallScore.toFixed(2)}</span></li>)}</ol></DetailBlock>
  </Dialog>;
}

function Meta({ label, value }) { return <div><dt>{label}</dt><dd>{value || '—'}</dd></div>; }

function MethodologyPanel({ onClose }) {
  return <Dialog title="Metodología" eyebrow="Lo que nos imponen" onClose={onClose} wide>
    <p className="libertas-method-lede">El tracker mide el efecto neto de una iniciativa desde un marco liberal-libertario. No mide constitucionalidad, calidad técnica, popularidad, intención política ni conveniencia general.</p>
    <DetailBlock title="Cinco criterios, el mismo peso"><div className="libertas-method-criteria">{CRITERIA.map((criterion, index) => <article key={criterion.id}><span>{index + 1}</span><h3>{criterion.label}</h3><p>{criterion.question}</p></article>)}</div></DetailBlock>
    <DetailBlock title="Cinco niveles"><div className="libertas-level-grid">{[2,1,0,-1,-2].map((score) => <div key={score}><RatingBadge score={score} /><p>{LEVELS[score].meaning}</p></div>)}</div></DetailBlock>
    <DetailBlock title="Cálculo del veredicto"><p>Los criterios Statu Quo no cuentan para el veredicto final. Se comparan cuántos criterios son favorables a la libertad y cuántos son contrarios. Gana el bloque con más criterios; si ambos tienen la misma cantidad, el resultado es Statu Quo. La intensidad —Pro o Hiper, Contra o Anti— se obtiene de la puntuación media del bloque ganador. Por ejemplo, cuatro criterios Statu Quo y uno Anti Libertas producen un veredicto final Anti Libertas.</p></DetailBlock>
  </Dialog>;
}

function LoadingState() { return <div className="libertas-state" role="status"><span className="libertas-loader" aria-hidden="true" />Cargando iniciativas…</div>; }
function ErrorState({ error, onRetry }) { return <div className="libertas-state is-error" role="alert"><strong>No se pudieron cargar los datos.</strong><pre>{error.message}</pre><button onClick={onRetry}>Reintentar</button></div>; }
function EmptyState({ onReset }) { return <div className="libertas-state"><strong>No hay iniciativas que coincidan.</strong><span>Prueba a retirar algún filtro o cambiar la búsqueda.</span><button onClick={onReset}>Restablecer filtros</button></div>; }

function LibertasTrackerPage() {
  const [records, setRecords] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [filters, setFilters] = useState({ ...EMPTY_FILTERS });
  const [sort, setSort] = useState({ key: 'date', direction: 'desc' });
  const [page, setPage] = useState(1);
  const [detailPanel, setDetailPanel] = useState(null);
  const [methodology, setMethodology] = useState(false);
  const PAGE_SIZE = 10;

  const load = () => { setLoading(true); setError(null); window.LibertasDataSource.load().then(setRecords).catch(setError).finally(() => setLoading(false)); };
  useEffect(load, []);
  const filtered = useMemo(() => Logic.filterAndSortLaws(records, filters, sort), [records, filters, sort]);
  const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const visible = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
  useEffect(() => setPage(1), [filters, sort]);
  const onSort = (key) => setSort((current) => ({ key, direction: current.key === key && current.direction === 'desc' ? 'asc' : 'desc' }));
  const updatedAt = records.reduce((latest, law) => law.updatedAt > latest ? law.updatedAt : latest, '');
  const openDetail = (law, initialCriterionId = null) => setDetailPanel({ law, initialCriterionId });

  return <div className="libertas-tracker"><div className="shell libertas-shell">
    <TrackerIntroduction updatedAt={updatedAt} onMethodology={() => setMethodology(true)} />
    {loading ? <LoadingState /> : error ? <ErrorState error={error} onRetry={load} /> : <>
      <TrackerFilters records={records} filters={filters} setFilters={setFilters} resultCount={filtered.length} />
      {filtered.length === 0 ? <EmptyState onReset={() => setFilters({ ...EMPTY_FILTERS })} /> : <>
        <LawTable records={visible} sort={sort} onSort={onSort} onDetail={openDetail} />
        <div className="libertas-cards">{visible.map((law) => <LawCard key={law.id} law={law} onDetail={openDetail} />)}</div>
        {pages > 1 && <nav className="libertas-pagination" aria-label="Paginación"><button disabled={page === 1} onClick={() => setPage((value) => value - 1)}>Anterior</button><span>Página {page} de {pages}</span><button disabled={page === pages} onClick={() => setPage((value) => value + 1)}>Siguiente</button></nav>}
      </>}
    </>}
    {detailPanel && <LawDetail key={`${detailPanel.law.id}-${detailPanel.initialCriterionId || 'summary'}`} {...detailPanel} onClose={() => setDetailPanel(null)} />}
    {methodology && <MethodologyPanel onClose={() => setMethodology(false)} />}
  </div></div>;
}

window.LibertasTrackerPage = LibertasTrackerPage;
})();
