// IEDF 2026 — main app
const { useState: useAppState, useMemo: useAppMemo } = React;

const D = window.IEDF_DATA;
const DIMS = { iedf_total: 'IEDF', estructura: 'Estructura', operacion: 'Operación', resultado: 'Resultado' };
const FOCUS_COLORS = ['#275b9b', '#d53e4f', '#66c2a5', '#f46d43', '#3288bd'];

// Fuentes y notas exactas del IEDF 2026 por indicador
const SERIES_NOTES = {
  ind01: {
    fuente: 'Elaboración propia con datos del CNPJE 2025 del INEGI (2017–2025) y proyecciones de población de la CONAPO.',
    nota: 'Promedio calculado a partir de las tasas por 100 mil habitantes de los estados con información disponible cada año. Para 2024 se imputaron Ciudad de México (con dato de 2023) y San Luis Potosí (con dato de 2020).'
  },
  ind02: {
    fuente: 'Elaboración propia con datos de cuentas públicas estatales, deflactor del PIB (SHCP) y proyecciones de población de la CONAPO (2016–2024).'
  },
  ind03: {
    fuente: 'Elaboración propia con datos del Índice de Transformación Digital de las Fiscalías en México 2024, Impunidad Cero.',
    nota: 'Solo disponible para 2024. No se muestra serie histórica.'
  },
  ind04: {
    fuente: 'Elaboración propia con datos de la ENVIPE del INEGI (2017–2025).'
  },
  ind05: {
    fuente: 'Elaboración propia con datos de la ENVIPE del INEGI (2017–2025).'
  },
  ind06: {
    fuente: 'Elaboración propia con datos del CNPJE del INEGI (2021–2025).',
    nota: 'Para 2017–2020 se utilizaron datos calculados en el IEDF 2021 con base en el MES y CNPJE; para 2020–2024 se utilizaron datos únicamente del CNPJE.'
  },
  ind07: {
    fuente: 'Elaboración propia con datos de la ENVIPE del INEGI (2017–2025).'
  },
  ind08: {
    fuente: 'Elaboración propia con datos del Índice de Impunidad en Homicidio Doloso (Impunidad Cero).',
    nota: 'Para 2016–2019 se consideran las estimaciones del Reporte 2020 (Zepeda y Jiménez). Para 2020–2021, estimaciones del informe Impunidad en homicidio doloso y feminicidio 2022, Impunidad Cero. Los valores de Campeche, Guanajuato y Jalisco fueron imputados con el promedio nacional (92.8 %).'
  },
  ctx03: {
    fuente: 'Elaboración propia con datos de carpetas de investigación del fuero común del SESNSP y el CNPJE del INEGI (2016–2025).'
  },
  ctx04: {
    fuente: 'Elaboración propia con datos de la incidencia delictiva del fuero común del SESNSP (2015–2025) y proyecciones de población a mitad de año de la CONAPO.'
  },
  ind09: {
    fuente: 'Elaboración propia con datos de constituciones estatales, leyes orgánicas y notas periodísticas (Impunidad Cero).'
  }
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "nav": "tabs",
  "paleta": "spectral9",
  "densidad": "amplia",
  "ranking": "columnas"
}/*EDITMODE-END*/;

const SECTIONS = [
  { id: 'ranking', num: '01', title: 'Ranking nacional' },
  { id: 'dimensiones', num: '02', title: 'Dimensiones' },
  { id: 'evolucion', num: '03', title: 'Evolución' },
  { id: 'perfil', num: '04', title: 'Perfil por entidad' },
];

function Seg({ options, value, onChange }) {
  return (
    <div style={{ display: 'inline-flex', border: `1.5px solid ${INK}` }}>
      {options.map(o => (
        <button key={o.value} onClick={() => onChange(o.value)} style={{
          fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 600, fontSize: 12.5, letterSpacing: '.02em',
          padding: '7px 14px', border: 'none', cursor: 'pointer', whiteSpace: 'nowrap',
          background: value === o.value ? INK : 'transparent',
          color: value === o.value ? '#faf9f6' : INK
        }}>{o.label}</button>
      ))}
    </div>
  );
}

function SectionHead({ num, title, kicker, children }) {
  return (
    <header style={{ marginBottom: 28 }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, paddingTop: 14 }}>
        <span style={{ fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 900, fontSize: 15, color: BRAND_BLUE }}>{num}</span>
        <h2 style={{ fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 900, fontSize: 'clamp(24px, 2.6vw, 34px)', letterSpacing: '-.015em', margin: 0 }}>{title}</h2>
      </div>
      {kicker && <p style={{ fontSize: 16.5, lineHeight: 1.55, maxWidth: 680, margin: '12px 0 0', color: '#44443f' }}>{kicker}</p>}
      {children}
    </header>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [tip, setTip] = useState(null);
  const [selected, setSelected] = useState('Nuevo Leon');
  const [hovered, setHovered] = useState(null);
  const [metric] = useState('iedf_total');
  const [xKey, setXKey] = useState('estructura');
  const [yKey, setYKey] = useState('resultado');
  const [serieInd, setSerieInd] = useState('ind05');
  const [focus, setFocus] = useState(['Nuevo Leon', 'Tlaxcala']);
  const [activeTab, setActiveTab] = useState('ranking');

  const palette = t.paleta === 'spectral5' ? SPECTRAL5 : SPECTRAL9;
  const maxW = t.densidad === 'compacta' ? 980 : 1180;

  const serieMetas = useAppMemo(() =>
    D.metadata.filter(m => D.series[m.id] && Object.keys(D.series[m.id]).length > 0 &&
      Object.values(D.series[m.id])[0].length > 1), []);
  const meta = serieMetas.find(m => m.id === serieInd) || serieMetas[0];

  const selectState = (ent) => {
    setSelected(ent);
    if (!focus.includes(ent)) setFocus(f => [ent, ...f].slice(0, 4));
  };
  const goProfile = (ent) => {
    selectState(ent);
    setHovered(null);
    setTip(null);
    setActiveTab('perfil');
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };
  const navTo = (id) => {
    setHovered(null);
    setTip(null);
    setActiveTab(id);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };
  const visible = (id) => activeTab === id;

  return (
    <div style={{ minHeight: '100vh' }}>
      {/* masthead */}
      <header data-screen-label="Portada" style={{ borderBottom: `3px solid ${INK}` }}>
        <div style={{ maxWidth: maxW, margin: '0 auto', padding: '54px 28px 38px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', flexWrap: 'wrap', gap: 8 }}>
            <span style={{ fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 800, fontSize: 13, letterSpacing: '.14em', textTransform: 'uppercase', color: BRAND_BLUE }}>Impunidad Cero, junio 2026</span>
          </div>
          <h1 style={{ fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 900, fontSize: 'clamp(40px, 6.5vw, 84px)', lineHeight: .98, letterSpacing: '-.025em', margin: '18px 0 0' }}>
            ¿Cómo se desempeñan las fiscalías?
          </h1>
          <p style={{ fontSize: 'clamp(16px, 1.6vw, 19px)', lineHeight: 1.55, maxWidth: 760, margin: '20px 0 0', color: '#44443f', textAlign: 'justify', hyphens: 'auto', WebkitHyphens: 'auto' }}>
            Las instituciones de procuración de justicia en México constituyen los primeros eslabones del proceso penal y pueden ser el principal cuello de botella para que los casos se investiguen y se esclarezcan. El <strong>Índice Estatal de Desempeño de Procuradurías y Fiscalías (IEDF)</strong> evalúa la procuración de justicia en las 32 entidades del país a partir de ocho indicadores construidos con fuentes de información pública. Los indicadores se agrupan en tres dimensiones: la <strong>estructura</strong> (personal, presupuesto y capacidades digitales de las fiscalías), la <strong>operación</strong> (cómo atienden y gestionan los casos) y los <strong>resultados</strong> (la confianza ciudadana, la propensión a denunciar, la efectividad en la resolución y los niveles de impunidad), para obtener una calificación de 0 a 100 comparable entre entidades y a lo largo del tiempo.
          </p>
          <a href="https://www.impunidadcero.org/articulo.php?id=227&t=indice-estatal-de-desempeno-de-procuradurias-y-fiscalias-iedf-2026"
            target="_blank" rel="noopener noreferrer" style={{
              display: 'inline-flex', alignItems: 'center', gap: 8, marginTop: 24,
              fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 700, fontSize: 14,
              letterSpacing: '.02em', color: BRAND_BLUE, textDecoration: 'none',
              borderBottom: `2px solid ${BRAND_BLUE}`, paddingBottom: 3
            }}>
            Ver la publicación completa <span aria-hidden="true">→</span>
          </a>

        </div>
      </header>

      {/* nav */}
      <nav style={{ position: 'sticky', top: 0, zIndex: 30, background: '#faf9f6', borderBottom: '1px solid #d8d6cd' }}>
        <div style={{ maxWidth: maxW, margin: '0 auto', padding: '0 28px', display: 'flex', gap: 4, overflowX: 'auto' }}>
          {SECTIONS.map(s => (
            <button key={s.id} onClick={() => navTo(s.id)} style={{
              fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 700, fontSize: 13, letterSpacing: '.03em',
              padding: '13px 16px', border: 'none', cursor: 'pointer', background: 'transparent',
              color: activeTab === s.id ? BRAND_BLUE : INK, whiteSpace: 'nowrap',
              boxShadow: activeTab === s.id ? `inset 0 -3px 0 ${BRAND_BLUE}` : 'none'
            }}><span style={{ color: BRAND_BLUE, marginRight: 6 }}>{s.num}</span>{s.title}</button>
          ))}
        </div>
      </nav>

      <main style={{ maxWidth: maxW, margin: '0 auto', padding: '0 28px' }}>
        {visible('ranking') && (
          <section id="ranking" data-screen-label="Ranking nacional" style={{ padding: '54px 0 30px' }}>
            <SectionHead num="01" title="Ranking nacional 2026"
              kicker="En esta edición del Índice, Nuevo León ocupa el primer lugar, con un total de 61.8 puntos, seguido de Guanajuato (61.6), Aguascalientes (58.3), Chihuahua (58.2) y Baja California (57.9). Por su parte, Tlaxcala se encuentra en el último lugar con 24.9 puntos, seguido de Morelos (25.0), Estado de México (25.9), Veracruz (29.9) y Guerrero (30.1)."></SectionHead>
            <div className="map-hero" style={{ maxWidth: 640, margin: '0 auto' }}>
              <MexicoMap data={D.ranking} metric={metric} palette={palette} selected={selected} onSelect={goProfile} onHover={setHovered} setTip={setTip} metricLabel={DIMS[metric]}></MexicoMap>
            </div>
            <div style={{ marginTop: 8 }}>
              {t.ranking === 'lista'
                ? <div style={{ maxWidth: 920, margin: '0 auto' }}><RankingChart data={D.ranking} metric={metric} palette={palette} selected={hovered || selected} onSelect={goProfile} setTip={setTip}></RankingChart></div>
                : <ColumnChart data={D.ranking} metric={metric} palette={palette} selected={hovered || selected} onSelect={goProfile} setTip={setTip}></ColumnChart>}
            </div>
            <p className="fineprint">Da clic en una entidad para abrir su perfil.</p>
          </section>
        )}

        {visible('dimensiones') && (
          <section id="dimensiones" data-screen-label="Dimensiones (scatter)" style={{ padding: '54px 0 30px' }}>
            <SectionHead num="02" title="Más recursos no siempre son mejores resultados"
              kicker="Tener más recursos no garantiza mejores resultados. Cada punto de esta gráfica es una entidad y su tamaño refleja su puntaje en el IEDF. Puedes elegir qué dos dimensiones comparar en los ejes (estructura, operación o resultado). Las líneas punteadas marcan la mediana nacional y dividen el plano en cuatro cuadrantes. El color indica la posición en el ranking: el azul señala a las entidades mejor posicionadas y el rojo a las de peor desempeño.">
              <div style={{ display: 'flex', gap: 18, marginTop: 18, flexWrap: 'wrap', alignItems: 'center' }}>
                <span className="axislabel">Eje X</span>
                <Seg value={xKey} onChange={v => { setXKey(v); if (v === yKey) setYKey(xKey); }} options={['estructura', 'operacion', 'resultado'].map(k => ({ value: k, label: DIMS[k] }))}></Seg>
                <span className="axislabel">Eje Y</span>
                <Seg value={yKey} onChange={v => { setYKey(v); if (v === xKey) setXKey(yKey); }} options={['estructura', 'operacion', 'resultado'].map(k => ({ value: k, label: DIMS[k] }))}></Seg>
              </div>
            </SectionHead>
            <ScatterChart data={D.ranking} xKey={xKey} yKey={yKey} palette={palette} selected={selected} onSelect={goProfile} setTip={setTip} labels={DIMS}></ScatterChart>
            <p className="fineprint">Da clic en un punto para abrir el perfil de la entidad.</p>
          </section>
        )}

        {visible('evolucion') && (
          <section id="evolucion" data-screen-label="Evolución 2016-2025" style={{ padding: '54px 0 30px' }}>
            <SectionHead num="03" title="Una década de procuración de justicia"
              kicker="Elige un indicador en el menú y la gráfica trazará su evolución con los datos más recientes disponibles del indicador. Las 32 entidades aparecen como líneas grises y la mediana nacional resaltada con una línea negra punteada. Selecciona hasta cuatro entidades para darles color y comparar su trayectoria frente al resto del país.">
              <div style={{ display: 'flex', gap: 12, marginTop: 18, flexWrap: 'wrap', alignItems: 'center' }}>
                <select className="stateselect" value={meta.id} onChange={e => setSerieInd(e.target.value)}>
                  {serieMetas.map(m => <option key={m.id} value={m.id}>{m.nombre}</option>)}
                </select>
                <span style={{ fontSize: 13, color: '#76766f' }}>{meta.unidad} · {meta.direccion === 'negativo' ? 'menos es mejor' : meta.direccion === 'positivo' ? 'más es mejor' : 'referencia'}</span>
              </div>
              <div style={{ display: 'flex', gap: 8, marginTop: 14, flexWrap: 'wrap' }}>
                {[...D.ranking].sort((a, b) => a.entidad_std.localeCompare(b.entidad_std)).map(d => {
                  const fi = focus.indexOf(d.entidad_std);
                  const on = fi >= 0;
                  return (
                    <button key={d.entidad_std} onClick={() =>
                      setFocus(f => on ? f.filter(x => x !== d.entidad_std) : [...f, d.entidad_std].slice(-4))
                    } style={{
                      fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 600, fontSize: 11.5, padding: '4px 9px',
                      border: `1.5px solid ${on ? FOCUS_COLORS[fi % FOCUS_COLORS.length] : '#c9c7bd'}`,
                      background: on ? FOCUS_COLORS[fi % FOCUS_COLORS.length] : 'transparent',
                      color: on ? '#faf9f6' : '#55554f', cursor: 'pointer'
                    }}>{d.entidad_std}</button>
                  );
                })}
              </div>
            </SectionHead>
            <SeriesChart seriesData={D.series[meta.id]} indicator={meta} focus={focus} palette={palette} setTip={setTip} focusColors={FOCUS_COLORS}></SeriesChart>
            {(() => {
              const sn = SERIES_NOTES[meta.id] || {};
              return (
                <div style={{ marginTop: 16, maxWidth: 860 }}>
                  <p className="fineprint" style={{ marginTop: 0 }}>
                    <strong>Fuente:</strong> {sn.fuente || meta.fuente}
                  </p>
                  {sn.nota && (
                    <p className="fineprint" style={{ marginTop: 6 }}>
                      <strong>Nota:</strong> {sn.nota}
                    </p>
                  )}
                </div>
              );
            })()}
          </section>
        )}

        {visible('perfil') && (
          <section id="perfil" data-screen-label="Perfil por entidad" style={{ padding: '54px 0 30px' }}>
            <SectionHead num="04" title="Perfil por entidad"
              kicker="Cada entidad cuenta con su propia radiografía. Elige un estado para conocer su posición en el ranking, su puntaje IEDF y su desempeño en cada dimensión frente al promedio nacional. Más abajo encontrarás el detalle de cada indicador y qué tan autónoma es su fiscalía."></SectionHead>
            <ProfileSection data={D} selected={selected} onSelect={selectState} palette={palette} setTip={setTip}></ProfileSection>
          </section>
        )}
      </main>

      <footer style={{ borderTop: `3px solid ${INK}`, marginTop: 50 }}>
        <div style={{ maxWidth: maxW, margin: '0 auto', padding: '26px 28px 60px', display: 'flex', justifyContent: 'space-between', gap: 20, flexWrap: 'wrap' }}>
          <div style={{ fontSize: 13.5, color: '#55554f', maxWidth: 620, lineHeight: 1.55 }}>
            <strong style={{ color: INK }}>IEDF 2026. Índice Estatal de Desempeño de Procuradurías y Fiscalías.</strong> Elaborado
            por Impunidad Cero. Disponible aquí: <a href="https://www.impunidadcero.org/articulo.php?id=227&t=indice-estatal-de-desempeno-de-procuradurias-y-fiscalias-iedf-2026" target="_blank" rel="noopener noreferrer" style={{ color: BRAND_BLUE, fontWeight: 700, textDecoration: 'underline' }}>ver la publicación</a>.
          </div>
          <div style={{ fontFamily: "Archivo, 'Helvetica Neue', sans-serif", fontWeight: 800, fontSize: 13, letterSpacing: '.14em', textTransform: 'uppercase', color: BRAND_BLUE }}>impunidadcero.org</div>
        </div>
      </footer>

      <Tooltip tip={tip}></Tooltip>

      <TweaksPanel>
        <TweakSection label="Navegación"></TweakSection>
        <TweakRadio label="Ranking" value={t.ranking} options={['columnas', 'lista']} onChange={v => setTweak('ranking', v)}></TweakRadio>
        <TweakRadio label="Ancho" value={t.densidad} options={['amplia', 'compacta']} onChange={v => setTweak('densidad', v)}></TweakRadio>
        <TweakSection label="Color"></TweakSection>
        <TweakColor label="Semáforo" value={t.paleta === 'spectral5' ? SPECTRAL5 : SPECTRAL9}
          options={[SPECTRAL9, SPECTRAL5]}
          onChange={v => setTweak('paleta', v.length === 5 ? 'spectral5' : 'spectral9')}></TweakColor>
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App></App>);
