// Luz Diaria — App principal React

const { useState, useEffect, useRef, useCallback } = React;

// ─── Helpers ────────────────────────────────────────────────────────────────

function hashDate(str) {
  let h = 0;
  for (let i = 0; i < str.length; i++) {
    h = Math.imul(31, h) + str.charCodeAt(i) | 0;
  }
  return Math.abs(h);
}

// PRNG determinista (mulberry32) para barajar siempre igual
function mulberry32(a) {
  return function () {
    a |= 0; a = a + 0x6D2B79F5 | 0;
    let t = Math.imul(a ^ a >>> 15, 1 | a);
    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}

// Permutación fija de [0..n-1] (mismo orden en cada carga gracias a la semilla)
function shuffledOrder(n, seed) {
  const arr = Array.from({ length: n }, (_, i) => i);
  const rnd = mulberry32(seed);
  for (let i = n - 1; i > 0; i--) {
    const j = Math.floor(rnd() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

// Días transcurridos desde una fecha base (índice de día estable)
function dayIndex(d) {
  const epoch = Date.UTC(2020, 0, 1);
  const today = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
  return Math.floor((today - epoch) / 86400000);
}

// Convierte 'YYYY-M-D' (fecha de instalación guardada) a Date local
function parseInstalled(str) {
  const [y, m, d] = str.split('-').map(Number);
  return new Date(y, m - 1, d);
}

let _orderV = null;
function getVerseForDay(offset = 0) {
  const d = new Date();
  d.setDate(d.getDate() + offset);
  const N = window.VERSES.length;
  // Recorre los N versículos sin repetir hasta agotarlos todos
  if (!_orderV || _orderV.length !== N) _orderV = shuffledOrder(N, 20240517);
  const i = ((dayIndex(d) % N) + N) % N;
  return window.VERSES[_orderV[i]];
}

// Fecha de Pascua (algoritmo de cómputo gregoriano)
function easterDate(year) {
  const a = year % 19, b = Math.floor(year / 100), c = year % 100;
  const d = Math.floor(b / 4), e = b % 4, f = Math.floor((b + 8) / 25);
  const g = Math.floor((b - f + 1) / 3), h = (19 * a + b - d - g + 15) % 30;
  const i = Math.floor(c / 4), k = c % 4;
  const l = (32 + 2 * e + 2 * i - h - k) % 7, m = Math.floor((a + 11 * h + 22 * l) / 451);
  const month = Math.floor((h + l - 7 * m + 114) / 31);
  const day = ((h + l - 7 * m + 114) % 31) + 1;
  return new Date(year, month - 1, day);
}

// Devuelve el id de ilustración para una fiesta católica en esa fecha, o null.
function getFeastInfo(d) {
  const y = d.getFullYear();
  // Fiestas móviles (relativas a la Pascua)
  const easter = easterDate(y);
  const movable = [
    [-7, 'palma', 'Domingo de Ramos'],
    [-3, 'caliz', 'Jueves Santo'],
    [-2, 'corona', 'Viernes Santo'],
    [0, 'cordero', 'Domingo de Resurrección'],
    [49, 'paloma', 'Pentecostés'],
    [56, 'trinidad', 'Santísima Trinidad'],
    [60, 'espigas', 'Corpus Christi'],
    [68, 'corazon', 'Sagrado Corazón'],
  ];
  for (const [off, id, name] of movable) {
    const t = new Date(easter);
    t.setDate(t.getDate() + off);
    if (t.getMonth() === d.getMonth() && t.getDate() === d.getDate()) return { id, name };
  }
  // Fiestas de fecha fija ('mes-día')
  const FIXED = {
    // Enero
    '1-1': ['maria', 'Santa María, Madre de Dios'],
    '1-6': ['estrella', 'Epifanía del Señor'],
    '1-17': ['san-antonio-abad', 'San Antonio Abad'],
    '1-28': ['tomas-aquino', 'Santo Tomás de Aquino'],
    '1-31': ['juan-bosco', 'San Juan Bosco'],
    // Febrero
    '2-2': ['vela', 'Presentación del Señor'],
    '2-3': ['san-blas', 'San Blas'],
    '2-5': ['felipe-jesus', 'San Felipe de Jesús'],
    '2-11': ['lourdes', 'Virgen de Lourdes'],
    '2-14': ['valentin', 'San Valentín'],
    // Marzo
    '3-17': ['san-patricio', 'San Patricio'],
    '3-19': ['san-jose', 'San José'],
    '3-25': ['angel', 'La Anunciación'],
    // Abril
    '4-29': ['catalina-siena', 'Santa Catalina de Siena'],
    // Mayo
    '5-13': ['fatima', 'Virgen de Fátima'],
    '5-22': ['santa-rita', 'Santa Rita'],
    // Junio
    '6-13': ['san-antonio', 'San Antonio de Padua'],
    '6-21': ['luis-gonzaga', 'San Luis Gonzaga'],
    '6-24': ['cordero', 'San Juan Bautista'],
    '6-29': ['llaves', 'San Pedro y San Pablo'],
    // Julio
    '7-11': ['san-benito', 'San Benito'],
    '7-16': ['carmen', 'Virgen del Carmen'],
    '7-22': ['magdalena', 'Santa María Magdalena'],
    '7-25': ['santiago', 'Santiago Apóstol'],
    '7-26': ['joaquin-ana', 'San Joaquín y Santa Ana'],
    // Agosto
    '8-8': ['domingo-guzman', 'Santo Domingo de Guzmán'],
    '8-11': ['clara-asis', 'Santa Clara de Asís'],
    '8-15': ['maria', 'Asunción de la Virgen'],
    '8-23': ['rosa-lima', 'Santa Rosa de Lima'],
    '8-28': ['agustin', 'San Agustín'],
    // Septiembre
    '9-14': ['cruz-rayos', 'Exaltación de la Santa Cruz'],
    '9-23': ['padre-pio', 'San Pío de Pietrelcina'],
    '9-29': ['miguel', 'San Miguel Arcángel'],
    '9-30': ['jeronimo', 'San Jerónimo'],
    // Octubre
    '10-4': ['francisco-asis', 'San Francisco de Asís'],
    '10-7': ['rosario', 'Virgen del Rosario'],
    '10-15': ['teresa-avila', 'Santa Teresa de Ávila'],
    '10-18': ['lucas', 'San Lucas Evangelista'],
    '10-28': ['judas-tadeo', 'San Judas Tadeo'],
    // Noviembre
    '11-1': ['estrella', 'Todos los Santos'],
    '11-2': ['vela', 'Fieles Difuntos'],
    '11-3': ['martin-porres', 'San Martín de Porres'],
    '11-11': ['martin-tours', 'San Martín de Tours'],
    '11-22': ['cecilia', 'Santa Cecilia'],
    '11-30': ['andres', 'San Andrés'],
    // Diciembre
    '12-6': ['nicolas', 'San Nicolás'],
    '12-8': ['maria', 'Inmaculada Concepción'],
    '12-9': ['juan-diego', 'San Juan Diego'],
    '12-12': ['rosa', 'Virgen de Guadalupe'],
    '12-13': ['lucia', 'Santa Lucía'],
    '12-24': ['estrella', 'Nochebuena'],
    '12-25': ['estrella', 'Navidad'],
    '12-27': ['juan-evangelista', 'San Juan Evangelista'],
  };
  const f = FIXED[`${d.getMonth() + 1}-${d.getDate()}`];
  return f ? { id: f[0], name: f[1] } : null;
}

const GENERIC_ART_IDS = new Set([
  'cruz','manos','biblia','lirio','ancla','pez','chi-rho','providencia',
  'ihs','manos-dios','vid','corona-real',
  'lampara','pastor','pan','puerta','arbol','incienso','mariposa','arco-iris','alfa-omega'
]);

let _orderA = null;
function getArtForDay(offset = 0) {
  const d = new Date();
  d.setDate(d.getDate() + offset);
  const list = window.LD_IMAGES || [];
  if (!list.length) return null;
  // Si el día es una fiesta católica, usa su ilustración específica
  const fi = getFeastInfo(d);
  if (fi) {
    const match = list.find(x => x.id === fi.id);
    if (match) return match;
  }
  // Si no, rota solo las ilustraciones genéricas (no santos ni personales)
  const generic = list.filter(x => GENERIC_ART_IDS.has(x.id));
  const M = generic.length;
  if (!_orderA || _orderA.length !== M) _orderA = shuffledOrder(M, 77110923);
  const i = ((dayIndex(d) % M) + M) % M;
  return generic[_orderA[i]];
}

function formatDateLabel(offset = 0) {
  const d = new Date();
  d.setDate(d.getDate() + offset);
  const opts = { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' };
  const str = d.toLocaleDateString('es-ES', opts);
  return (str.charAt(0).toUpperCase() + str.slice(1))
    .replace(/\bde ([a-záéíóúüñ]+)\b/, (_, m) => 'de ' + m.charAt(0).toUpperCase() + m.slice(1));
}

function getDayBadge(offset) {
  if (offset === 0) return null;
  if (offset === -1) return 'Ayer';
  return `Hace ${Math.abs(offset)} días`;
}

// Clave estable por día para el diario (YYYY-M-D)
function dateKeyFor(offset = 0) {
  const d = new Date();
  d.setDate(d.getDate() + offset);
  return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}

// Fecha personal (cumpleaños, aniversarios, etc.) para ese día, o null
function getDateInfo(offset = 0) {
  const d = new Date();
  d.setDate(d.getDate() + offset);
  const key = `${d.getMonth() + 1}-${d.getDate()}`;
  return (window.LD_DATES && window.LD_DATES[key]) || null;
}

// Resuelve ids de ilustración a objetos de LD_IMAGES
function resolveArts(ids) {
  const list = window.LD_IMAGES || [];
  return (ids || []).map(id => list.find(i => i.id === id)).filter(Boolean);
}

// ─── Compartir como imagen (tarjeta en canvas) ────────────────────────────────

function wrapLines(ctx, text, maxWidth) {
  const words = text.split(' ');
  const lines = [];
  let line = '';
  for (const w of words) {
    const test = line ? line + ' ' + w : w;
    if (ctx.measureText(test).width > maxWidth && line) {
      lines.push(line);
      line = w;
    } else {
      line = test;
    }
  }
  if (line) lines.push(line);
  return lines;
}

function svgToImage(art, size, color) {
  return new Promise((resolve, reject) => {
    const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="${size}" height="${size}" fill="none" stroke="${color}" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" style="color:${color}">${art.svg}</svg>`;
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
  });
}

async function buildShareImage(verse, art, feastName) {
  const W = 1080, M = 110, maxW = W - M * 2;
  const C = { bg: '#f7efe1', gold: '#c79a4b', goldD: '#977230', text: '#3b2f20', textM: '#6c5b45' };

  try { await document.fonts.ready; } catch (_) {}

  const canvas = document.createElement('canvas');
  canvas.width = W;
  const ctx = canvas.getContext('2d');

  // Medir para calcular alto dinámico
  ctx.font = 'italic 46px "EB Garamond", Georgia, serif';
  const verseLines = wrapLines(ctx, `“${verse.text}”`, maxW);
  ctx.font = 'italic 33px "EB Garamond", Georgia, serif';
  const prayerLines = wrapLines(ctx, verse.prayer, maxW);

  const artSize = 200;
  let H = 120;                 // margen superior + marca
  H += artSize + 40;           // ilustración
  if (feastName) H += 44;      // nombre de la fiesta
  H += 70;                     // referencia
  H += 34;                     // divisor
  H += verseLines.length * 62 + 50;
  H += 44;                     // etiqueta oración
  H += prayerLines.length * 46 + 50;
  H += 120;                    // pie
  H = Math.max(H, 960);        // alto mínimo agradable; crece con el contenido

  canvas.height = H;

  // Fondo
  ctx.fillStyle = C.bg;
  ctx.fillRect(0, 0, W, H);

  // Marco dorado
  ctx.strokeStyle = C.gold;
  ctx.lineWidth = 2;
  const inset = 34, r = 28;
  ctx.beginPath();
  if (ctx.roundRect) ctx.roundRect(inset, inset, W - inset * 2, H - inset * 2, r);
  else ctx.rect(inset, inset, W - inset * 2, H - inset * 2);
  ctx.stroke();

  ctx.textAlign = 'center';
  let y = 110;

  // Marca
  ctx.fillStyle = C.gold;
  ctx.font = '600 30px "Cinzel", Georgia, serif';
  ctx.fillText('✦  L U Z   D I A R I A  ✦', W / 2, y);
  y += 60;

  // Ilustración
  try {
    const img = await svgToImage(art, artSize, C.gold);
    ctx.drawImage(img, W / 2 - artSize / 2, y, artSize, artSize);
  } catch (_) {}
  y += artSize - 8;

  // Nombre de la fiesta litúrgica (pegado al dibujo)
  if (feastName) {
    ctx.fillStyle = C.gold;
    ctx.font = 'italic 30px "EB Garamond", Georgia, serif';
    ctx.fillText(feastName, W / 2, y);
    y += 56;
  } else {
    y += 28;
  }

  // Referencia
  ctx.fillStyle = C.goldD;
  ctx.font = '600 42px "Cinzel", Georgia, serif';
  ctx.fillText(verse.ref.toUpperCase(), W / 2, y + 20);
  y += 56;

  // Divisor
  ctx.beginPath();
  ctx.moveTo(W / 2 - 50, y); ctx.lineTo(W / 2 + 50, y);
  ctx.strokeStyle = C.gold; ctx.lineWidth = 1.5; ctx.stroke();
  y += 50;

  // Versículo
  ctx.fillStyle = C.text;
  ctx.font = 'italic 46px "EB Garamond", Georgia, serif';
  for (const ln of verseLines) { ctx.fillText(ln, W / 2, y); y += 62; }
  y += 30;

  // Etiqueta oración: cruz dorada vectorial + texto, centrados como bloque
  ctx.fillStyle = C.gold;
  ctx.font = '600 24px "Cinzel", Georgia, serif';
  const label = 'ORACIÓN DEL DÍA';
  const labelW = ctx.measureText(label).width;
  const crossW = 12, gap = 14;
  const startX = W / 2 - (crossW + gap + labelW) / 2;
  // cruz dibujada con líneas (color dorado garantizado, sin depender de la fuente)
  const cx = startX + crossW / 2;
  ctx.strokeStyle = C.gold;
  ctx.lineWidth = 2.4;
  ctx.lineCap = 'round';
  ctx.beginPath();
  ctx.moveTo(cx, y - 18); ctx.lineTo(cx, y - 1);
  ctx.moveTo(cx - 6, y - 12); ctx.lineTo(cx + 6, y - 12);
  ctx.stroke();
  // texto alineado a la izquierda justo después de la cruz
  ctx.textAlign = 'left';
  ctx.fillText(label, startX + crossW + gap, y);
  ctx.textAlign = 'center';
  y += 48;

  // Oración
  ctx.fillStyle = C.textM;
  ctx.font = 'italic 33px "EB Garamond", Georgia, serif';
  for (const ln of prayerLines) { ctx.fillText(ln, W / 2, y); y += 46; }

  // Pie
  ctx.fillStyle = C.gold;
  ctx.font = 'italic 30px "EB Garamond", Georgia, serif';
  ctx.fillText('Luz Diaria', W / 2, H - 60);

  return new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
}

// ─── Exportar / Importar datos ───────────────────────────────────────────────

function exportData() {
  const data = {
    version: 1,
    favorites: JSON.parse(localStorage.getItem('ld_favorites') || '[]'),
    journal: JSON.parse(localStorage.getItem('ld_journal') || '{}'),
    installed: localStorage.getItem('ld_installed') || null,
    exported: new Date().toISOString(),
  };
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
  const file = new File([blob], 'luz-diaria-respaldo.json', { type: 'application/json' });
  if (navigator.canShare && navigator.canShare({ files: [file] })) {
    navigator.share({ files: [file], title: 'Respaldo Luz Diaria' }).catch(() => {});
    return;
  }
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'luz-diaria-respaldo.json';
  a.click();
  URL.revokeObjectURL(url);
}

// ─── Dedication Screen ──────────────────────────────────────────────────────

function DedicationScreen({ name, onEnter }) {
  const [visible, setVisible] = useState(false);
  useEffect(() => { setTimeout(() => setVisible(true), 100); }, []);

  return (
    <div className={`dedication ${visible ? 'dedication--in' : ''}`} onClick={onEnter}>
      <div className="dedication__rays">
        {[...Array(12)].map((_, i) => (
          <div key={i} className="ray" style={{ '--i': i }} />
        ))}
      </div>

      <div className="dedication__content">
        <div className="dedication__ornament">✦ ✦ ✦</div>
        <p className="dedication__para">Para</p>
        <h1 className="dedication__name">{name}</h1>
        <p className="dedication__nick">(Mosha Mosha)</p>
        <div className="dedication__divider" />
        <p className="dedication__sub">
          En nuestro<br />
          <span className="dedication__anni">20° Aniversario</span>
          <span className="dedication__novios">+5 de novios!</span>
        </p>
        <p className="dedication__msg">
          Que cada día encuentres aquí<br />
          un refugio de paz, fuerza<br />y amor divino.
        </p>
        <p className="dedication__love">Te amosinos!!</p>
        <div className="dedication__ornament">✦ ✦ ✦</div>
        <p className="dedication__tap">Toca para entrar</p>
      </div>
    </div>
  );
}

// ─── Verse Card ─────────────────────────────────────────────────────────────

function VerseCard({ verse, animKey, animDir, isFav, onFav }) {
  return (
    <div key={animKey} className={`vcard vcard--${animDir}`}>
      <div className="vcard__top">
        <div className="vcard__ref">{verse.ref}</div>
        <button
          className={`vcard__fav ${isFav ? 'vcard__fav--faved' : ''}`}
          onClick={onFav}
          aria-label={isFav ? 'Quitar de guardados' : 'Guardar este día'}
          title={isFav ? 'Quitar de guardados' : 'Guardar este día'}
        >
          <svg width="22" height="22" viewBox="0 0 24 24" fill={isFav ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
          </svg>
        </button>
      </div>
      <div className="vcard__divider" />
      <blockquote className="vcard__text">
        &ldquo;{verse.text}&rdquo;
      </blockquote>
    </div>
  );
}

// ─── Daily Art ───────────────────────────────────────────────────────────────

function ArtSvg({ art, className }) {
  return (
    <svg
      className={className}
      viewBox="0 0 120 120"
      fill="none"
      stroke="currentColor"
      strokeWidth="2.4"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-label={art.label}
      role="img"
      dangerouslySetInnerHTML={{ __html: art.svg }}
    />
  );
}

function DailyArt({ art, labelText, animKey }) {
  if (!art) return null;
  return (
    <div className="daily-art" key={animKey}>
      <ArtSvg art={art} className="daily-art__svg" />
      {labelText && <p className="daily-art__label">{labelText}</p>}
    </div>
  );
}

// ─── Special Date (fechas personales) ─────────────────────────────────────────

function SpecialNote({ info, arts }) {
  if (!info) return null;
  return (
    <div className="special">
      <div className="special__ornament">✦</div>
      <h2 className="special__title">{info.title}</h2>
      {info.note ? <p className="special__note">{info.note}</p> : null}
      {arts && arts.length ? (
        <div className="special__arts">
          {arts.map((a, i) => <ArtSvg key={i} art={a} className="special__svg" />)}
        </div>
      ) : null}
    </div>
  );
}

// ─── Prayer Section ──────────────────────────────────────────────────────────

function PrayerSection({ prayer, isOpen, onToggle }) {
  return (
    <div className="prayer">
      <button className="prayer__toggle" onClick={onToggle} aria-expanded={isOpen}>
        <span className="prayer__icon">{'✝\uFE0E'}</span>
        <span>Oración del día</span>
        <span className={`prayer__chevron ${isOpen ? 'prayer__chevron--open' : ''}`}>▾</span>
      </button>
      <div className={`prayer__body ${isOpen ? 'prayer__body--open' : ''}`}>
        <p className="prayer__text">{prayer}</p>
      </div>
    </div>
  );
}

// ─── Journal / Diario ─────────────────────────────────────────────────────────

function JournalSection({ dayKey, isOpen, onToggle }) {
  const [text, setText] = useState('');

  useEffect(() => {
    const all = JSON.parse(localStorage.getItem('ld_journal') || '{}');
    setText(all[dayKey] || '');
  }, [dayKey]);

  const save = (val) => {
    setText(val);
    const all = JSON.parse(localStorage.getItem('ld_journal') || '{}');
    if (val.trim()) all[dayKey] = val;
    else delete all[dayKey];
    localStorage.setItem('ld_journal', JSON.stringify(all));
  };

  return (
    <div className="journal">
      <button className="journal__toggle" onClick={onToggle} aria-expanded={isOpen}>
        <span className="journal__icon">✎</span>
        <span>Mi nota de hoy{text.trim() ? ' •' : ''}</span>
        <span className={`journal__chevron ${isOpen ? 'journal__chevron--open' : ''}`}>▾</span>
      </button>
      <div className={`journal__body ${isOpen ? 'journal__body--open' : ''}`}>
        <textarea
          className="journal__input"
          value={text}
          onChange={(e) => save(e.target.value)}
          placeholder="Escribe un pensamiento, una gratitud o una intención…"
          rows={4}
        />
        <p className="journal__hint">Tus notas se guardan solo en este dispositivo 🤍</p>
      </div>
    </div>
  );
}

// ─── Action Bar ──────────────────────────────────────────────────────────────

function ActionBar({ hasFavorites, onViewFavorites, onShare, onPrev, onNext, canGoPrev, canGoNext, showToast }) {
  return (
    <div className="actions">
      <button
        className={`actions__btn ${!canGoPrev ? 'actions__btn--disabled' : ''}`}
        onClick={onPrev}
        disabled={!canGoPrev}
        title="Día anterior"
        aria-label="Día anterior"
      >
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <polyline points="15 18 9 12 15 6"/>
        </svg>
      </button>

      <button
        className="actions__btn actions__btn--heart"
        onClick={onViewFavorites}
        title="Ver días guardados"
        aria-label="Ver días guardados"
      >
        <svg width="22" height="22" viewBox="0 0 24 24" fill={hasFavorites ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
        </svg>
      </button>

      <button className="actions__btn actions__btn--share" onClick={onShare} title="Compartir" aria-label="Compartir versículo">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
          <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>
        </svg>
      </button>

      <button
        className={`actions__btn ${!canGoNext ? 'actions__btn--disabled' : ''}`}
        onClick={onNext}
        disabled={!canGoNext}
        title="Día siguiente"
        aria-label="Día siguiente"
      >
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <polyline points="9 18 15 12 9 6"/>
        </svg>
      </button>

      {showToast && (
        <div className="toast">{showToast}</div>
      )}
    </div>
  );
}

// ─── Favorites Screen ────────────────────────────────────────────────────────

function FavoritesScreen({ favorites, onBack, onRemove, onImport }) {
  const [msg, setMsg] = useState('');
  const favVerses = window.VERSES.filter(v => favorites.includes(v.id));

  const handleExport = () => {
    exportData();
    setMsg('¡Respaldo listo!');
    setTimeout(() => setMsg(''), 2500);
  };

  const handleImport = () => {
    onImport((ok) => {
      setMsg(ok ? '¡Datos restaurados!' : 'Archivo inválido');
      setTimeout(() => setMsg(''), 2500);
    });
  };

  return (
    <div className="favscreen">
      <div className="favscreen__header">
        <h2 className="favscreen__title">Mis Favoritos</h2>
      </div>

      {favVerses.length === 0 ? (
        <div className="favscreen__empty">
          <div className="favscreen__empty-icon">♡</div>
          <p>Aún no tienes versículos guardados.</p>
          <p>Toca el corazón para guardar los que más te toquen.</p>
        </div>
      ) : (
        <div className="favscreen__list">
          {favVerses.map(v => (
            <div key={v.id} className="favcard">
              <div className="favcard__ref">{v.ref}</div>
              <p className="favcard__text">&ldquo;{v.text}&rdquo;</p>
              <button className="favcard__remove" onClick={() => onRemove(v.id)} aria-label="Eliminar favorito">
                ✕
              </button>
            </div>
          ))}
        </div>
      )}
      <div className="actions">
        <button className="actions__btn" onClick={onBack} aria-label="Volver">
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <polyline points="15 18 9 12 15 6"/>
          </svg>
        </button>
        <button className="actions__btn" onClick={handleExport} aria-label="Guardar respaldo" title="Guardar respaldo">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
            <polyline points="17 8 12 3 7 8"/>
            <line x1="12" y1="3" x2="12" y2="15"/>
          </svg>
        </button>
        <button className="actions__btn" onClick={handleImport} aria-label="Restaurar datos" title="Restaurar datos">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
            <polyline points="7 10 12 15 17 10"/>
            <line x1="12" y1="15" x2="12" y2="3"/>
          </svg>
        </button>
        {msg && <div className="toast">{msg}</div>}
      </div>
    </div>
  );
}

// ─── Main App ────────────────────────────────────────────────────────────────

function App() {
  const [screen, setScreen] = useState(() =>
    localStorage.getItem('ld_visited') ? 'main' : 'dedication'
  );
  const [dayOffset, setDayOffset] = useState(0);
  const [installedDate, setInstalledDate] = useState(() => localStorage.getItem('ld_installed'));
  const minOffset = (() => {
    if (!installedDate) return -60;
    return -(dayIndex(new Date()) - dayIndex(parseInstalled(installedDate)));
  })();
  const [favorites, setFavorites] = useState(() =>
    JSON.parse(localStorage.getItem('ld_favorites') || '[]')
  );
  const [animKey, setAnimKey] = useState(0);
  const [animDir, setAnimDir] = useState('in');
  const [prayerOpen, setPrayerOpen] = useState(false);
  const [journalOpen, setJournalOpen] = useState(false);
  const [toast, setToast] = useState('');

  const touchStartX = useRef(null);

  const verse = getVerseForDay(dayOffset);
  const special = getDateInfo(dayOffset);
  const specialArts = special ? resolveArts(special.art) : [];
  const _dl = new Date(); _dl.setDate(_dl.getDate() + dayOffset);
  const feastInfo = getFeastInfo(_dl);
  const art = getArtForDay(dayOffset);           // fiesta o rotación
  const artLabel = feastInfo ? feastInfo.name : (art ? art.label : '');
  const isFav = favorites.includes(verse.id);

  const navigate = useCallback((direction) => {
    setAnimDir(direction);
    setAnimKey(k => k + 1);
    setPrayerOpen(false);
    setJournalOpen(false);
  }, []);

  const flashToast = (msg) => {
    setToast(msg);
    setTimeout(() => setToast(''), 2500);
  };

  const canGoPrev = dayOffset > minOffset;
  const goBack = () => {
    if (canGoPrev) {
      navigate('left');
      setDayOffset(d => d - 1);
    }
  };

  const goForward = () => {
    if (dayOffset < 0) {
      navigate('right');
      setDayOffset(d => d + 1);
    }
  };

  const handleEnterFromDedication = () => {
    localStorage.setItem('ld_visited', '1');
    if (!localStorage.getItem('ld_installed')) {
      const t = new Date();
      const dateStr = `${t.getFullYear()}-${t.getMonth() + 1}-${t.getDate()}`;
      localStorage.setItem('ld_installed', dateStr);
      setInstalledDate(dateStr);
    }
    setScreen('main');
  };

  const toggleFavorite = () => {
    const next = isFav
      ? favorites.filter(id => id !== verse.id)
      : [...favorites, verse.id];
    setFavorites(next);
    localStorage.setItem('ld_favorites', JSON.stringify(next));
  };

  const handleImport = (callback) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,application/json';
    input.onchange = (e) => {
      const file = e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = (ev) => {
        try {
          const data = JSON.parse(ev.target.result);
          if (data.favorites && Array.isArray(data.favorites)) {
            localStorage.setItem('ld_favorites', JSON.stringify(data.favorites));
            setFavorites(data.favorites);
          }
          if (data.journal && typeof data.journal === 'object') {
            localStorage.setItem('ld_journal', JSON.stringify(data.journal));
          }
          if (data.installed) {
            const current = localStorage.getItem('ld_installed');
            // Conservar la fecha de instalación más antigua (ver más días atrás)
            const pick = (!current)
              ? data.installed
              : (parseInstalled(data.installed) < parseInstalled(current) ? data.installed : current);
            localStorage.setItem('ld_installed', pick);
            setInstalledDate(pick);
          }
          callback(true);
        } catch (_) {
          callback(false);
        }
      };
      reader.readAsText(file);
    };
    input.click();
  };

  const shareVerse = async () => {
    const text = `📖 ${verse.ref}\n\n"${verse.text}"\n\n🙏 Oración del día\n${verse.prayer}\n\n— Luz Diaria`;
    // Intento 1: compartir como imagen (tarjeta ilustrada)
    try {
      const blob = await buildShareImage(verse, art, feastInfo ? feastInfo.name : null);
      if (blob) {
        const file = new File([blob], 'luz-diaria.png', { type: 'image/png' });
        if (navigator.canShare && navigator.canShare({ files: [file] })) {
          await navigator.share({ files: [file] });
          return;
        }
        // Sin compartir-archivos: descargar la imagen
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'luz-diaria.png';
        a.click();
        URL.revokeObjectURL(url);
        flashToast('¡Imagen guardada!');
        return;
      }
    } catch (e) {
      if (e && e.name === 'AbortError') return; // el usuario canceló
    }
    // Intento 2 (fallback): compartir/copiar texto
    try {
      if (navigator.share) {
        await navigator.share({ text });
      } else {
        await navigator.clipboard.writeText(text);
        flashToast('¡Versículo copiado!');
      }
    } catch (_) {}
  };

  // Swipe gestures
  const handleTouchStart = (e) => {
    touchStartX.current = e.touches[0].clientX;
  };

  const handleTouchEnd = (e) => {
    if (touchStartX.current === null) return;
    const dx = e.changedTouches[0].clientX - touchStartX.current;
    if (Math.abs(dx) > 55) {
      if (dx < 0) goBack();
      else goForward();
    }
    touchStartX.current = null;
  };

  if (screen === 'dedication') {
    return <DedicationScreen name="Petty" onEnter={handleEnterFromDedication} />;
  }

  if (screen === 'favorites') {
    return (
      <FavoritesScreen
        favorites={favorites}
        onBack={() => setScreen('main')}
        onRemove={(id) => {
          const next = favorites.filter(f => f !== id);
          setFavorites(next);
          localStorage.setItem('ld_favorites', JSON.stringify(next));
        }}
        onImport={handleImport}
      />
    );
  }

  const dayBadge = getDayBadge(dayOffset);

  return (
    <div
      className="app"
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
    >
      {/* Header */}
      <header className="header">
        <div className="header__brand">
          <span className="header__cross">✦</span>
          <span className="header__title">Luz Diaria</span>
        </div>
      </header>

      {/* Date */}
      <div className="datebar">
        {dayBadge && <span className="datebar__badge">{dayBadge}</span>}
        <p className="datebar__date">{formatDateLabel(dayOffset)}</p>
      </div>

      {/* Verse */}
      <main className="main">
        {special && <SpecialNote info={special} arts={specialArts} />}

        <VerseCard verse={verse} animKey={animKey} animDir={animDir} isFav={isFav} onFav={toggleFavorite} />

        <PrayerSection
          prayer={verse.prayer}
          isOpen={prayerOpen}
          onToggle={() => setPrayerOpen(o => !o)}
        />

        <DailyArt art={art} labelText={artLabel} animKey={animKey} />

        <JournalSection
          dayKey={dateKeyFor(dayOffset)}
          isOpen={journalOpen}
          onToggle={() => setJournalOpen(o => !o)}
        />
      </main>

      {/* Actions */}
      <ActionBar
        hasFavorites={favorites.length > 0}
        onViewFavorites={() => setScreen('favorites')}
        onShare={shareVerse}
        onPrev={goBack}
        onNext={goForward}
        canGoPrev={canGoPrev}
        canGoNext={dayOffset < 0}
        showToast={toast}
      />

      {/* Swipe hint (shown only first few times) */}
    </div>
  );
}

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