﻿// ============================================================
// REVISTA ULTRAMONTANO - codigo del sitio publico
// Para modificar el sitio, edita este archivo y volve a subirlo.
// La base de datos (Supabase) ya esta configurada abajo.
// ============================================================

const SUPABASE_URL = "https://hqtmhlmqwliaxdjjzleb.supabase.co";
const SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhxdG1obG1xd2xpYXhkamp6bGViIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzkxNjc2NTEsImV4cCI6MjA5NDc0MzY1MX0.ToQHqMiZnGs3nQMZpM08WMxIxz0aLzafsG_ZpMQ_mvw";

const { useState, useEffect } = React;
let sb = null;
try { sb = supabase.createClient(SUPABASE_URL, SUPABASE_KEY); } catch (err) {}

function fmtFecha(f) {
  try {
    const d = new Date(f);
    const m = ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"];
    return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
  } catch (e) { return f; }
}

function Etq({ t }) {
  return <span className="etq">{t}</span>;
}

// Convierte URL de YouTube/Vimeo/Drive/etc a la URL de embed adecuada
// Convierte "Dardo Juan Calderón" a "dardo-juan-calderon"
function slug(s) {
  return (s || "").toLowerCase()
    .normalize("NFD").replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}

function videoEmbed(url) {
  if (!url) return null;
  const u = url.trim();
  // YouTube: youtube.com/watch?v=XXXX  o  youtu.be/XXXX  o  ya un embed
  let m = u.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{6,})/);
  if (m) return "https://www.youtube.com/embed/" + m[1];
  // Vimeo: vimeo.com/123456789
  m = u.match(/vimeo\.com\/(?:video\/)?(\d+)/);
  if (m) return "https://player.vimeo.com/video/" + m[1];
  // Google Drive: drive.google.com/file/d/FILEID/view  -> /preview
  m = u.match(/drive\.google\.com\/file\/d\/([a-zA-Z0-9_-]+)/);
  if (m) return "https://drive.google.com/file/d/" + m[1] + "/preview";
  // Gloria.tv: NO devolvemos URL — el render usa el componente GloriaEmbed con oEmbed
  m = u.match(/gloria\.tv\/(?:post|video|embed)\/([a-zA-Z0-9]+)/);
  if (m) return null; // marca especial: usar GloriaEmbed
  // Cualquier otra URL: la usamos tal cual
  return u;
}

function esGloriaTv(url) {
  return /gloria\.tv\/(?:post|video|embed)\//.test(url || "");
}

// Componente para embeber Gloria.tv usando su API oficial oEmbed
function GloriaEmbed({ url }) {
  const [html, setHtml] = useState(null);
  const [err, setErr] = useState(false);

  useEffect(() => {
    let cancelado = false;
    (async () => {
      try {
        const oembedUrl = "https://gloria.tv/oembed/?url=" +
          encodeURIComponent(url) + "&format=json";
        const r = await fetch(oembedUrl);
        if (!r.ok) throw new Error("oEmbed " + r.status);
        const d = await r.json();
        if (!cancelado && d.html) setHtml(d.html);
        else if (!cancelado) setErr(true);
      } catch (e) {
        if (!cancelado) setErr(true);
      }
    })();
    return () => { cancelado = true; };
  }, [url]);

  if (err) {
    // Fallback: link a Gloria.tv si oEmbed falla
    return (
      <a href={url} target="_blank" rel="noopener noreferrer"
        style={{ display: "block", padding: 20, background: "#f7f6f2",
          border: "1px solid #ddd", borderRadius: 8, textAlign: "center",
          color: "var(--wine)", textDecoration: "none" }}>
        ▶ Ver video en Gloria.tv
      </a>
    );
  }
  if (!html) {
    return <div style={{ padding: 20, textAlign: "center", color: "#888" }}>
      Cargando video…
    </div>;
  }
  return <div className="gloria-embed" dangerouslySetInnerHTML={{ __html: html }} />;
}

// Estilo de imagen de fondo según posición y modo elegidos por artículo
const POS_MAP = {
  "center": "center center",
  "top-center": "center top",
  "bottom-center": "center bottom",
  "left": "left center",
  "right": "right center",
  // intermedias (porcentajes para puntos a mitad de camino)
  "top-mid": "center 25%",        // entre arriba y centro
  "bottom-mid": "center 75%",     // entre abajo y centro
  "left-mid": "25% center",       // entre izquierda y centro
  "right-mid": "75% center",      // entre derecha y centro
  // compatibilidad con valores viejos
  "top-left": "left top",
  "top-right": "right top",
  "bottom-left": "left bottom",
  "bottom-right": "right bottom"
};
function bg(art) {
  // acepta el artículo (objeto) o una url string
  const url = typeof art === "string" ? art : (art && art.imagen_url);
  if (!url) return {};
  const pos = (art && art.img_pos) ? (POS_MAP[art.img_pos] || "center center") : "center center";
  const fit = (art && art.img_fit) || "cover";
  let size = "cover";
  if (fit === "alto") size = "auto 100%";
  else if (fit === "ancho") size = "100% auto";
  return {
    backgroundImage: `url(${url})`,
    backgroundSize: size,
    backgroundPosition: pos,
    backgroundRepeat: "no-repeat"
  };
}

function PlayIcon() {
  return (
    <div style={{ position: "absolute", top: "50%", left: "50%",
      transform: "translate(-50%,-50%)", width: 56, height: 56,
      borderRadius: "50%", background: "rgba(0,0,0,.55)",
      display: "flex", alignItems: "center", justifyContent: "center",
      pointerEvents: "none" }}>
      <svg viewBox="0 0 24 24" width="26" height="26" fill="#fff"
        style={{ marginLeft: 4 }}>
        <path d="M8 5v14l11-7z"/>
      </svg>
    </div>
  );
}

function Card({ a, abrir }) {
  const esAcad = a.categorias && a.categorias.slug === "academico";
  return (
    <div className={"card" + (esAcad ? " acad" : "")} onClick={() => abrir(a)}>
      <div className="img" style={{ ...bg(a), position: "relative" }}>
        {a.video_url && <PlayIcon />}
      </div>
      <div className="bd">
        <Etq t={a.categorias ? a.categorias.nombre : ""} />
        <h3>{a.titulo}</h3>
        <div className="meta">por {a.autores ? a.autores.nombre : ""} · {fmtFecha(a.fecha)}</div>
      </div>
    </div>
  );
}

function Home({ arts: arts0, abrir, irAutor, irAutores }) {
  // Presentación no se lista en el sitio (vive en Quiénes somos)
  const arts = arts0.filter(a => a.slug !== "presentacion");
  // Destacados grande/laterales (1, 2, 3) van arriba en el bloque destacado
  const dest = arts.filter(a => a.destacada > 0 && a.destacada <= 3)
    .sort((x, y) => x.destacada - y.destacada);
  const grande = dest[0], lat = dest.slice(1, 3);
  // El resto va en Últimas, pero los de destacada=4 al tope
  const noDest = arts.filter(a => !a.destacada || a.destacada === 0 || a.destacada === 4);
  // Orden: primero los de destacada=4, después los normales por fecha
  noDest.sort((a, b) => {
    const da = a.destacada === 4 ? 1 : 0;
    const db = b.destacada === 4 ? 1 : 0;
    if (da !== db) return db - da;
    return 0; // ya vienen ordenados por fecha desde la query
  });
  const resto = noDest.slice(0, 10);
  const mas = [...arts].sort((a, b) => (b.vistas || 0) - (a.vistas || 0)).slice(0, 5);
  const aus = [...new Set(arts.map(a => a.autores && a.autores.nombre).filter(Boolean))]
    .filter(x => x !== "Editorial").slice(0, 5);

  return (
    <div className="wrap">
      {grande && (
        <div className="destac" style={{ marginTop: 24 }}>
          <div className={"big" + (grande.categorias && grande.categorias.slug === "academico" ? " acad" : "")}
            onClick={() => abrir(grande)}>
            <div className="img" style={bg(grande)}>
              <Etq t={grande.categorias ? grande.categorias.nombre : ""} />
              {grande.video_url && <PlayIcon />}
            </div>
            <div className="bd">
              <h2>{grande.titulo}</h2>
              <div className="mt">por {grande.autores ? grande.autores.nombre : ""} · {fmtFecha(grande.fecha)}</div>
              <p>{grande.bajada}</p>
            </div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
            {lat.map(a => (
              <div key={a.id}
                className={"lat" + (a.categorias && a.categorias.slug === "academico" ? " acad" : "")}
                onClick={() => abrir(a)}>
                <div className="img" style={{ ...bg(a), position: "relative" }}>
                  {a.video_url && <PlayIcon />}
                </div>
                <div className="bd">
                  <Etq t={a.categorias ? a.categorias.nombre : ""} />
                  <h3>{a.titulo}</h3>
                  <div className="mt">por {a.autores ? a.autores.nombre : ""}</div>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {mas.length > 0 && <div className="sec">LO MÁS LEÍDO</div>}
      <div className="rank">
        {mas.map((a, i) => (
          <div key={a.id} className="it" onClick={() => abrir(a)}>
            <div className="n">{i + 1}</div>
            <div>
              <div className="tt">{a.titulo}</div>
              <div className="meta" style={{ marginTop: 4 }}>{a.autores ? a.autores.nombre : ""}</div>
            </div>
          </div>
        ))}
      </div>

      <div className="sec">ÚLTIMAS PUBLICACIONES</div>
      <div className="grid2">
        {resto.map(a => <Card key={a.id} a={a} abrir={abrir} />)}
      </div>

      {aus.length > 0 && (
        <div className="sec" onClick={() => irAutores && irAutores()}
          style={{ cursor: irAutores ? "pointer" : "default" }}>
          POR AUTOR
          {irAutores && <span style={{
            fontSize: 12, marginLeft: 12, color: "var(--wine)",
            fontFamily: "Helvetica,Arial,sans-serif", textTransform: "none",
            letterSpacing: 0
          }}>ver todos →</span>}
        </div>
      )}
      <div className="autores">
        {aus.map(nm => (
          <div key={nm} className="au" onClick={() => irAutor && irAutor(nm)}
            style={{ cursor: "pointer" }}>
            <div className="nm">{nm}</div>
            <div className="meta" style={{ marginTop: 4 }}>
              {arts.filter(a => a.autores && a.autores.nombre === nm).length} artículo(s)
            </div>
          </div>
        ))}
      </div>

      <div className="sec">TE PUEDE INTERESAR</div>
      <div className="grid2">
        {resto.slice(0, 4).map(a => <Card key={"r" + a.id} a={a} abrir={abrir} />)}
      </div>
    </div>
  );
}

// Iconos SVG oficiales de redes sociales
const IcoWa = () => <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z"/></svg>;
const IcoX = () => <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>;
const IcoFb = () => <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"/></svg>;
const IcoCopy = () => <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>;

function Articulo({ art, arts, abrir, volver }) {
  // Registrar visita (filtra repetidos por sesión + día, y bots básicos)
  useEffect(() => {
    if (!art || !art.id) return;
    (async () => {
      try {
        const ua = (navigator.userAgent || "").toLowerCase();
        // Detección básica de bots
        const esBot = /bot|crawl|spider|slurp|facebookexternalhit|whatsapp|preview|telegram/i.test(ua);
        // Hash simple basado en UA + un id de sesión persistente
        let sid = localStorage.getItem("ums_sid");
        if (!sid) {
          sid = Math.random().toString(36).slice(2) + Date.now().toString(36);
          localStorage.setItem("ums_sid", sid);
        }
        const hash = btoa((ua + "|" + sid).slice(0, 80)).slice(0, 32);
        await sb.rpc("registrar_visita", {
          p_articulo_id: art.id,
          p_visitante_hash: hash,
          p_es_bot: esBot
        });
      } catch (e) { /* si falla, no rompe la lectura */ }
    })();
  }, [art && art.id]);

  function enlaceArticulo() {
    return window.location.origin + "/" + art.slug;
  }
  const url = art.slug ? enlaceArticulo() : window.location.href;
  const txt = encodeURIComponent(art.titulo);
  function copiar() {
    const ok = () => alert("Enlace copiado:\n" + url);
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(url).then(ok).catch(() => { prompt("Copiá este enlace:", url); });
    } else { prompt("Copiá este enlace:", url); }
  }
  // Render del cuerpo: detecta HTML o texto plano, procesa marcadores [IMG:...] y [VIDEO:...]
  const parr = (() => {
    const cuerpo = art.cuerpo || "";
    const esHtml = /<(p|h2|h3|div|ul|ol|blockquote|br)[\s>]/i.test(cuerpo);
    // Lista de bloques a renderizar
    let bloques = [];
    if (esHtml) {
      // Dividir por bloques HTML pero respetando marcadores que aparecen
      // dentro de párrafos o como párrafos solos.
      // 1. Reemplazar marcadores que están dentro de <p>...[IMG:...]...</p>
      //    sacándolos a bloque propio. Usamos un parser DOM en el browser.
      try {
        const div = document.createElement("div");
        div.innerHTML = cuerpo;
        // Recorremos los hijos directos
        Array.from(div.children).forEach(nodo => {
          // Si el nodo es <p> y su texto entero es un marcador, sacamos el marcador
          const textoNodo = nodo.textContent.trim();
          const mImg = textoNodo.match(/^\[IMG:([^|\]]+)(?:\|([^|\]]*))?(?:\|([^\]]*))?\]$/);
          const mVid = textoNodo.match(/^\[VIDEO:([^|\]]+)(?:\|([^\]]*))?\]$/);
          if (mImg) {
            bloques.push({ tipo: "img", url: mImg[1].trim(),
              tam: (mImg[2] || "grande").trim(), pie: (mImg[3] || "").trim() });
          } else if (mVid) {
            bloques.push({ tipo: "video", url: mVid[1].trim(), cap: (mVid[2] || "").trim() });
          } else {
            bloques.push({ tipo: "html", html: nodo.outerHTML });
          }
        });
      } catch (e) {
        // Si falla el parser DOM, mostramos como bloque único
        bloques.push({ tipo: "html", html: cuerpo });
      }
    } else {
      // Texto plano clásico: dividir por línea en blanco
      bloques = cuerpo.split(/\n\n+/).map(p => {
        const t = p.trim();
        if (!t) return null;
        if (t.startsWith("<strong>") && t.endsWith("</strong>"))
          return { tipo: "h2", texto: t.replace(/<\/?strong>/g, "") };
        const mImg = t.match(/^\[IMG:([^|\]]+)(?:\|([^|\]]*))?(?:\|([^\]]*))?\]$/);
        if (mImg) return { tipo: "img", url: mImg[1].trim(),
          tam: (mImg[2] || "grande").trim(), pie: (mImg[3] || "").trim() };
        const mVid = t.match(/^\[VIDEO:([^|\]]+)(?:\|([^\]]*))?\]$/);
        if (mVid) return { tipo: "video", url: mVid[1].trim(), cap: (mVid[2] || "").trim() };
        return { tipo: "p", html: t };
      }).filter(Boolean);
    }
    // Renderizar cada bloque
    return bloques.map((b, i) => {
      if (b.tipo === "h2") return <h2 key={i}>{b.texto}</h2>;
      if (b.tipo === "p") return <p key={i} dangerouslySetInnerHTML={{ __html: b.html }} />;
      if (b.tipo === "html") return <div key={i} dangerouslySetInnerHTML={{ __html: b.html }} />;
      if (b.tipo === "img") {
        let estiloImg = { display: "block", margin: "20px auto",
          maxWidth: "100%", height: "auto", borderRadius: 8 };
        if (b.tam === "chica") {
          estiloImg = { float: "right", maxWidth: 280, margin: "6px 0 14px 22px",
            height: "auto", borderRadius: 6 };
        } else if (b.tam === "mediana") {
          estiloImg = { display: "block", margin: "20px auto",
            maxWidth: 480, height: "auto", borderRadius: 8 };
        }
        return (
          <figure key={i} style={{ margin: "20px 0" }}>
            <img src={b.url} alt={b.pie} style={estiloImg} />
            {b.pie && <figcaption style={{
              fontSize: 14, fontStyle: "italic", color: "#666",
              textAlign: "center", marginTop: 6
            }}>{b.pie}</figcaption>}
          </figure>
        );
      }
      if (b.tipo === "video") {
        return (
          <figure key={i} style={{ margin: "24px 0" }}>
            {esGloriaTv(b.url) ? (
              <GloriaEmbed url={b.url} />
            ) : (
              <div style={{ position: "relative", paddingTop: "56.25%",
                height: 0, overflow: "hidden", borderRadius: 8 }}>
                <iframe src={videoEmbed(b.url)}
                  style={{ position: "absolute", top: 0, left: 0,
                    width: "100%", height: "100%", border: 0 }}
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                  allowFullScreen />
              </div>
            )}
            {b.cap && <figcaption style={{
              fontSize: 14, fontStyle: "italic", color: "#666",
              textAlign: "center", marginTop: 6
            }}>{b.cap}</figcaption>}
          </figure>
        );
      }
      return null;
    });
  })();

  // Relacionados: mismo autor + misma categoría, sin el actual, máximo 6
  const todos = arts || [];
  const mismoAutor = todos.filter(x => x.id !== art.id
    && art.autores && x.autores && x.autores.nombre === art.autores.nombre);
  const mismaCat = todos.filter(x => x.id !== art.id
    && art.categorias && x.categorias && x.categorias.slug === art.categorias.slug
    && (!art.autores || !x.autores || x.autores.nombre !== art.autores.nombre));
  const relac = [...mismoAutor.slice(0, 4), ...mismaCat.slice(0, 4)].slice(0, 6);

  const Compartir = ({ tam }) => {
    const sz = tam === "chico" ? 30 : 38;
    const fs = tam === "chico" ? 11 : 13;
    const btn = (bg, fn, ico, label) => (
      <button onClick={fn} title={label} style={{
        width: sz, height: sz, padding: 0, borderRadius: "50%",
        border: 0, background: bg, color: "#fff", cursor: "pointer",
        display: "inline-flex", alignItems: "center", justifyContent: "center"
      }}>{ico}</button>
    );
    return (
      <div style={{ display: "flex", gap: 8, alignItems: "center",
        marginTop: tam === "chico" ? 10 : 22, marginBottom: tam === "chico" ? 18 : 0,
        flexWrap: "wrap" }}>
        {tam === "chico" && <span style={{ fontSize: fs, color: "#888",
          fontFamily: "Helvetica,Arial,sans-serif", marginRight: 4 }}>Compartir:</span>}
        {btn("#25D366", () => window.open("https://wa.me/?text=" + txt + "%20" + encodeURIComponent(url)), <IcoWa/>, "WhatsApp")}
        {btn("#000", () => window.open("https://twitter.com/intent/tweet?url=" + encodeURIComponent(url) + "&text=" + txt), <IcoX/>, "X / Twitter")}
        {btn("#1877F2", () => window.open("https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(url)), <IcoFb/>, "Facebook")}
        {btn("#6e1f2a", copiar, <IcoCopy/>, "Copiar enlace")}
      </div>
    );
  };

  return (
    <div className="art-layout">
      <div className="art art-main">
        {art.imagen_url && <img className="hero" src={art.imagen_url} alt="" />}
        <div style={{ marginTop: 14 }}>
          <Etq t={art.categorias ? art.categorias.nombre : ""} />
        </div>
        <h1>{art.titulo}</h1>
        <div className="info">
          por {art.autores ? art.autores.nombre : ""} · {fmtFecha(art.fecha)}
          {(art.vistas || 0) > 1 && (
            <>
              {" · "}
              <svg viewBox="0 5820 1282 510"
                style={{ width: 32, height: 13, flexShrink: 0,
                  verticalAlign: "middle", display: "inline-block",
                  marginRight: 4 }}
                fill="currentColor">
                <g transform="translate(0,6400) scale(0.1,-0.1)">
                  <path d="M2725 5579 c-607 -42 -1171 -235 -1745 -597 -235 -149 -451 -242 -645 -277 -179 -33 -200 -45 -249 -134 -51 -95 -74 -213 -83 -431 -9 -220 9 -263 141 -347 110 -71 187 -156 240 -265 38 -77 51 -123 81 -273 146 -721 368 -1210 709 -1563 140 -145 316 -278 559 -421 784 -461 1572 -496 2444 -109 820 363 1294 960 1579 1988 58 207 97 293 166 366 113 120 282 163 588 151 246 -10 369 -56 488 -181 88 -93 144 -202 252 -491 98 -262 169 -413 277 -595 454 -761 1183 -1339 1915 -1519 201 -50 322 -64 533 -64 344 1 633 65 959 213 500 228 824 537 1063 1015 108 215 182 436 253 750 79 351 137 524 213 633 52 75 93 106 165 127 70 21 133 84 158 157 32 99 -3 419 -62 547 -61 134 -145 207 -339 291 -183 79 -381 184 -580 309 -497 310 -920 459 -1530 538 -199 25 -692 26 -851 0 -636 -102 -1164 -380 -1759 -927 -193 -178 -299 -182 -625 -25 -274 131 -390 161 -600 152 -185 -8 -314 -49 -491 -158 -112 -69 -176 -87 -247 -69 -76 19 -123 53 -284 206 -385 368 -741 624 -1047 754 -108 46 -424 134 -623 174 -367 73 -697 97 -1023 75z m608 -370 c640 -79 1217 -436 1552 -959 117 -182 222 -445 266 -669 30 -150 37 -425 15 -586 -88 -659 -513 -1228 -1143 -1531 -695 -334 -1547 -282 -2188 134 -769 498 -1101 1395 -824 2227 284 854 1147 1430 2097 1399 79 -3 180 -9 225 -15z m6746 -69 c398 -27 761 -145 1073 -349 469 -307 773 -743 886 -1271 24 -116 26 -143 26 -365 0 -222 -2 -249 -26 -365 -181 -846 -870 -1467 -1783 -1606 -152 -23 -469 -23 -629 0 -787 114 -1442 618 -1701 1311 -211 564 -140 1192 192 1695 273 413 672 707 1169 860 172 53 342 80 629 98 11 1 85 -3 164 -8z"/>
                </g>
              </svg>
              {art.vistas}
            </>
          )}
        </div>
        {art.bajada && <div className="lead">{art.bajada}</div>}
        <div className="separador-art"></div>
        <Compartir tam="chico" />
        {art.video_url && (
          esGloriaTv(art.video_url) ? (
            <div style={{ margin: "20px 0" }}>
              <GloriaEmbed url={art.video_url} />
            </div>
          ) : (
            <div style={{ margin: "20px 0", position: "relative",
              paddingTop: "56.25%", height: 0, overflow: "hidden", borderRadius: 8 }}>
              <iframe src={videoEmbed(art.video_url)}
                style={{ position: "absolute", top: 0, left: 0,
                  width: "100%", height: "100%", border: 0 }}
                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                allowFullScreen />
            </div>
          )
        )}
        {parr}
        <Compartir tam="grande" />
      </div>
      <aside className="art-side">
        {art.autores && (
          <div className="side-bloque">
            <div className="side-titulo">Sobre el autor</div>
            <div style={{ display: "flex", gap: 12, alignItems: "center", marginBottom: 10 }}>
              {art.autores.foto_url
                ? <img src={art.autores.foto_url} alt=""
                    style={{ width: 60, height: 60, borderRadius: "50%", objectFit: "cover" }} />
                : <div style={{ width: 60, height: 60, borderRadius: "50%", background: "#e8e8e8" }} />}
              <div className="side-autor-nombre">{art.autores.nombre}</div>
            </div>
            {art.autores.bio &&
              <div className="side-autor-bio">{art.autores.bio}</div>}
          </div>
        )}
        {relac.length > 0 && (
          <div className="side-bloque">
            <div className="side-titulo">Para seguir leyendo</div>
            {relac.map(r => (
              <div key={r.id} className="side-item" onClick={() => abrir && abrir(r)}>
                {r.imagen_url && <div className="side-img" style={{ backgroundImage: `url(${r.imagen_url})` }} />}
                <div>
                  <div className="side-it-tt">{r.titulo}</div>
                  <div className="side-it-mt">{r.autores ? r.autores.nombre : ""}</div>
                </div>
              </div>
            ))}
          </div>
        )}
      </aside>
    </div>
  );
}

function Quienes({ arts, cfg }) {
  const pres = (arts || []).find(a => a.slug === "presentacion");
  const retrato = cfg && cfg.retrato_calderon;
  const parr = pres ? (pres.cuerpo || "").split(/\n\n+/).map((p, i) => {
    const t = p.trim();
    if (t.startsWith("<strong>") && t.endsWith("</strong>"))
      return <h2 key={i}>{t.replace(/<\/?strong>/g, "")}</h2>;
    return <p key={i} dangerouslySetInnerHTML={{ __html: t }} />;
  }) : null;

  return (
    <div className="art">
      <h1>Quiénes somos</h1>
      <p>Revista Ultramontano es una publicación de actualidad y de pensamiento contrarrevolucionario, fiel al Magisterio perenne de la Iglesia y a la sana doctrina.</p>
      <p>El nombre Ultramontano reivindica aquella postura que, frente a los nacionalismos eclesiásticos y las tentaciones de adaptar la fe a los poderes del mundo, mira siempre «más allá de los montes»: hacia Roma y la doctrina inmutable que la Iglesia ha custodiado a lo largo de los siglos.</p>
      <h2>Dirección</h2>
      {retrato && (
        <img src={retrato} alt="Dr. Dardo Juan Calderón"
          style={{ float: "right", width: 200, maxWidth: "40%", marginLeft: 20,
            marginBottom: 12, borderRadius: 6, background: "#fff" }} />
      )}
      <p>La revista es dirigida por el Dr. Dardo Juan Calderón, abogado en ejercicio del foro en la Provincia de Mendoza, Argentina, donde nació en 1958. Titulado en la Universidad de Mendoza y padre de numerosa familia. Es hijo de don Rubén Calderón Bouchet (1918-2012), destacado filósofo argentino dedicado al estudio de las ideas políticas y del pensamiento tradicional.</p>

      {pres && (
        <div style={{ clear: "both", marginTop: 36, paddingTop: 24,
          borderTop: "2px solid var(--wine)" }}>
          <h2 style={{ marginTop: 0 }}>{pres.titulo}</h2>
          {pres.bajada && <div className="lead">{pres.bajada}</div>}
          {parr}
        </div>
      )}
    </div>
  );
}

const PHP_URL = "enviar.php";

function Suscribirse({ emailInicial }) {
  const [f, setF] = useState({ nombre: "", apellido: "", email: emailInicial || "" });
  const [estado, setEstado] = useState(null);
  function set(k, v) { setF(p => ({ ...p, [k]: v })); }

  async function enviar() {
    if (!f.nombre || !f.apellido || !f.email) { setEstado("incompleto"); return; }
    if (!/^[^@]+@[^@]+\.[^@]+$/.test(f.email)) { setEstado("invalido"); return; }
    setEstado("enviando");
    let guardoEnBase = false;
    let mandoMail = false;
    // 1. Guardar en la base
    try {
      if (sb) {
        const { error } = await sb.from("suscriptores").insert({
          nombre: f.nombre, apellido: f.apellido, email: f.email
        });
        if (error) { console.error("Error guardando suscriptor:", error); }
        else { guardoEnBase = true; }
      }
    } catch (e) { console.error("Excepción guardando suscriptor:", e); }
    // 2. Mandar aviso por mail
    try {
      const r = await fetch(PHP_URL, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          tipo: "suscripcion", email: f.email,
          nombre: f.nombre + " " + f.apellido
        })
      });
      const d = await r.json().catch(() => null);
      if (d && d.ok) { mandoMail = true; }
      else { console.error("PHP devolvió:", d); }
    } catch (e) { console.error("Excepción enviando mail:", e); }
    // Si al menos una de las dos funcionó, damos por ok
    if (guardoEnBase || mandoMail) {
      setEstado("ok");
      setF({ nombre: "", apellido: "", email: "" });
    } else {
      setEstado("error");
    }
  }

  const inp = { width: "100%", padding: "13px 14px", fontSize: 15,
    border: "1px solid #ccc", borderRadius: 6, fontFamily: "inherit", marginBottom: 14 };

  return (
    <div className="art" style={{ maxWidth: 560 }}>
      <h1 style={{ textAlign: "center" }}>Suscríbete ya</h1>
      <p style={{ fontSize: 18, color: "#555", marginBottom: 28, textAlign: "center" }}>
        Recibe lo último de Revista Ultramontano
      </p>
      {estado === "ok" && <div className="aviso ok">¡Gracias! Tu suscripción fue registrada.</div>}
      {estado === "error" && <div className="aviso err">No se pudo registrar. Intentá más tarde.</div>}
      {estado === "incompleto" && <div className="aviso err">Completá nombre, apellido y correo.</div>}
      {estado === "invalido" && <div className="aviso err">Ingresá un email válido.</div>}
      <input style={inp} placeholder="Nombre" value={f.nombre}
        onChange={e => set("nombre", e.target.value)} />
      <input style={inp} placeholder="Apellido" value={f.apellido}
        onChange={e => set("apellido", e.target.value)} />
      <input style={inp} placeholder="Correo electrónico" type="email" value={f.email}
        onChange={e => set("email", e.target.value)} />
      <div style={{ textAlign: "center" }}>
        <button onClick={enviar} disabled={estado === "enviando"}
          style={{ marginTop: 6, background: "var(--navy)", color: "#fff",
            border: 0, padding: "13px 40px", borderRadius: 24, fontSize: 15,
            cursor: "pointer", fontFamily: "Helvetica,Arial,sans-serif" }}>
          {estado === "enviando" ? "Enviando…" : "Suscribirse"}
        </button>
      </div>
    </div>
  );
}

function Contacto({ titulo, intro }) {
  const [f, setF] = useState({ nombre: "", email: "", mensaje: "" });
  const [estado, setEstado] = useState(null);
  function set(k, v) { setF(p => ({ ...p, [k]: v })); }

  async function enviar() {
    if (!f.nombre || !f.email || !f.mensaje) { setEstado("incompleto"); return; }
    if (!/^[^@]+@[^@]+\.[^@]+$/.test(f.email)) { setEstado("invalido"); return; }
    setEstado("enviando");
    try {
      const r = await fetch(PHP_URL, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ tipo: "contacto", ...f })
      });
      const d = await r.json();
      setEstado(d.ok ? "ok" : "error");
      if (d.ok) setF({ nombre: "", email: "", mensaje: "" });
    } catch (e) { setEstado("error"); }
  }

  const inp = { width: "100%", padding: "12px 14px", fontSize: 15,
    border: "1px solid #ccc", borderRadius: 6, fontFamily: "inherit", marginBottom: 14 };

  return (
    <div className="art" style={{ maxWidth: 600 }}>
      <h1>{titulo || "Escribir al director"}</h1>
      <p style={{ color: "#555", marginBottom: 22 }}>
        {intro || "Tu mensaje llegará directamente a la dirección de la revista."}
      </p>
      {estado === "ok" && <div className="aviso ok">Mensaje enviado. Gracias por escribir.</div>}
      {estado === "error" && <div className="aviso err">No se pudo enviar. Intentá más tarde.</div>}
      {estado === "incompleto" && <div className="aviso err">Completá todos los campos.</div>}
      {estado === "invalido" && <div className="aviso err">Ingresá un email válido.</div>}
      <input style={inp} placeholder="Tu nombre" value={f.nombre}
        onChange={e => set("nombre", e.target.value)} />
      <input style={inp} placeholder="Tu email" type="email" value={f.email}
        onChange={e => set("email", e.target.value)} />
      <textarea style={{ ...inp, minHeight: 160, resize: "vertical" }}
        placeholder="Tu mensaje" value={f.mensaje}
        onChange={e => set("mensaje", e.target.value)} />
      <button onClick={enviar} disabled={estado === "enviando"}
        style={{ background: "var(--navy)", color: "#fff", border: 0,
          padding: "13px 36px", borderRadius: 6, fontSize: 15, cursor: "pointer",
          fontFamily: "Helvetica,Arial,sans-serif" }}>
        {estado === "enviando" ? "Enviando…" : "Enviar mensaje"}
      </button>
    </div>
  );
}

// Devuelve un SVG según el código WMO de Open-Meteo
function ClimaIcon({ code, isNight }) {
  const c = code;
  const sz = 18;
  const sun = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none"
      stroke="#ffd966" strokeWidth="2" strokeLinecap="round">
      <circle cx="12" cy="12" r="4" fill="#ffd966" />
      <line x1="12" y1="2" x2="12" y2="5"/><line x1="12" y1="19" x2="12" y2="22"/>
      <line x1="2" y1="12" x2="5" y2="12"/><line x1="19" y1="12" x2="22" y2="12"/>
      <line x1="4.93" y1="4.93" x2="7" y2="7"/><line x1="17" y1="17" x2="19.07" y2="19.07"/>
      <line x1="4.93" y1="19.07" x2="7" y2="17"/><line x1="17" y1="7" x2="19.07" y2="4.93"/>
    </svg>
  );
  const moon = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="#e9d77a">
      <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
    </svg>
  );
  const partlyDay = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none">
      <circle cx="8" cy="9" r="3" fill="#ffd966"/>
      <path d="M17 19a3 3 0 0 0 0-6 4.5 4.5 0 0 0-8.7-1A3.5 3.5 0 0 0 9 19h8z"
        fill="#fff" stroke="#fff" strokeWidth=".5"/>
    </svg>
  );
  const partlyNight = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none">
      <path d="M9 5a4 4 0 0 0 4 4 3 3 0 0 1-1 1.6A3.5 3.5 0 0 0 8 8c0-1.1.4-2.1 1-3z" fill="#e9d77a"/>
      <path d="M17 19a3 3 0 0 0 0-6 4.5 4.5 0 0 0-8.7-1A3.5 3.5 0 0 0 9 19h8z"
        fill="#fff"/>
    </svg>
  );
  const cloud = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="#fff">
      <path d="M19 18a4 4 0 0 0 0-8 6 6 0 0 0-11.6-1.3A4.5 4.5 0 0 0 8 18h11z"/>
    </svg>
  );
  const rain = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none">
      <path d="M19 14a4 4 0 0 0 0-8 6 6 0 0 0-11.6-1.3A4.5 4.5 0 0 0 8 14h11z" fill="#fff"/>
      <line x1="8" y1="17" x2="7" y2="21" stroke="#8ab8e6" strokeWidth="2" strokeLinecap="round"/>
      <line x1="12" y1="17" x2="11" y2="21" stroke="#8ab8e6" strokeWidth="2" strokeLinecap="round"/>
      <line x1="16" y1="17" x2="15" y2="21" stroke="#8ab8e6" strokeWidth="2" strokeLinecap="round"/>
    </svg>
  );
  const storm = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none">
      <path d="M19 14a4 4 0 0 0 0-8 6 6 0 0 0-11.6-1.3A4.5 4.5 0 0 0 8 14h11z" fill="#fff"/>
      <polygon points="12,15 9,21 12,21 10,24 15,18 12,18" fill="#ffd966"/>
    </svg>
  );
  const snow = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none">
      <path d="M19 14a4 4 0 0 0 0-8 6 6 0 0 0-11.6-1.3A4.5 4.5 0 0 0 8 14h11z" fill="#fff"/>
      <text x="7" y="22" fill="#fff" fontSize="10">❄</text>
      <text x="13" y="22" fill="#fff" fontSize="10">❄</text>
    </svg>
  );
  const fog = (
    <svg viewBox="0 0 24 24" width={sz} height={sz} fill="none" stroke="#fff" strokeWidth="2" strokeLinecap="round">
      <line x1="4" y1="10" x2="20" y2="10"/>
      <line x1="3" y1="14" x2="19" y2="14"/>
      <line x1="6" y1="18" x2="20" y2="18"/>
    </svg>
  );
  // WMO codes: https://open-meteo.com/en/docs
  if (c === 0) return isNight ? moon : sun;                  // despejado
  if (c === 1) return isNight ? partlyNight : partlyDay;     // mayormente despejado
  if (c === 2) return isNight ? partlyNight : partlyDay;     // parcialmente nublado
  if (c === 3) return cloud;                                 // nublado
  if (c === 45 || c === 48) return fog;                      // niebla
  if (c >= 51 && c <= 67) return rain;                       // llovizna / lluvia
  if (c >= 71 && c <= 77) return snow;                       // nieve
  if (c >= 80 && c <= 82) return rain;                       // chubascos
  if (c >= 85 && c <= 86) return snow;                       // nieve fuerte
  if (c >= 95) return storm;                                 // tormenta
  return isNight ? moon : sun;
}

function BarraTop() {
  const [info, setInfo] = useState({ ciudad: "", pais: "", temp: null, code: null });
  const [ahora, setAhora] = useState(new Date());
  const [esMobile, setEsMobile] = useState(typeof window !== "undefined" && window.innerWidth <= 760);

  // Reloj que se actualiza cada minuto
  useEffect(() => {
    const t = setInterval(() => setAhora(new Date()), 60000);
    return () => clearInterval(t);
  }, []);

  // Detectar resize a mobile
  useEffect(() => {
    function onResize() { setEsMobile(window.innerWidth <= 760); }
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // Geolocalización por IP (ipinfo.io con token) + temperatura
  useEffect(() => {
    (async () => {
      try {
        // Primero ver si tenemos los datos en cache (compartido con estadísticas)
        let geo = null;
        try {
          const cache = localStorage.getItem("ums_geo");
          if (cache) {
            const obj = JSON.parse(cache);
            // Validar que el cache tenga TODOS los campos esperados (formato nuevo)
            if (obj.ts && obj.lat && obj.lng &&
                (Date.now() - obj.ts) < 7 * 24 * 3600 * 1000) {
              geo = obj;
            }
          }
        } catch (e) { /* cache rota, ignorar */ }

        // Si no hay cache, pedir a ipinfo.io con token
        if (!geo) {
          const r = await fetch("https://ipinfo.io/json?token=0f4469a755486a");
          const d = await r.json();
          if (d) {
            // ipinfo.io devuelve "loc" como "lat,lng"
            const loc = (d.loc || "").split(",");
            geo = {
              ciudad: d.city || "",
              pais: d.country || "",
              region: d.region || "",
              lat: loc[0] || null,
              lng: loc[1] || null,
              ts: Date.now()
            };
            localStorage.setItem("ums_geo", JSON.stringify(geo));
          }
        }

        if (!geo) return;

        // Buscar el nombre completo del país (ipinfo devuelve código tipo "AR")
        const nombresPais = {
          AR: "Argentina", US: "Estados Unidos", ES: "España", MX: "México",
          UY: "Uruguay", CL: "Chile", BR: "Brasil", CO: "Colombia", PE: "Perú",
          FR: "Francia", IT: "Italia", DE: "Alemania", PT: "Portugal",
          GB: "Reino Unido", PY: "Paraguay", BO: "Bolivia", VE: "Venezuela",
          EC: "Ecuador", CR: "Costa Rica", CU: "Cuba", DO: "República Dominicana",
          CA: "Canadá", AU: "Australia", JP: "Japón", CN: "China"
        };
        const nombrePais = nombresPais[geo.pais] || geo.pais;

        let temp = null, code = null;
        if (geo.lat && geo.lng) {
          const r2 = await fetch("https://api.open-meteo.com/v1/forecast?latitude="
            + geo.lat + "&longitude=" + geo.lng + "&current=temperature_2m,weather_code");
          const d2 = await r2.json();
          if (d2 && d2.current) {
            if (typeof d2.current.temperature_2m === "number") {
              temp = Math.round(d2.current.temperature_2m);
            }
            if (typeof d2.current.weather_code === "number") {
              code = d2.current.weather_code;
            }
          }
        }
        setInfo({ ciudad: geo.ciudad, pais: nombrePais, temp, code });
      } catch (e) { /* si falla, la barra muestra solo fecha y hora */ }
    })();
  }, []);

  const diasL = ["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"];
  const diasC = ["Dom","Lun","Mar","Mié","Jue","Vie","Sáb"];
  const mesesL = ["enero","febrero","marzo","abril","mayo","junio",
    "julio","agosto","septiembre","octubre","noviembre","diciembre"];
  const mesesC = ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"];

  const fecha = esMobile
    ? (diasC[ahora.getDay()] + " " + ahora.getDate() + " " + mesesC[ahora.getMonth()] + " " + ahora.getFullYear())
    : (diasL[ahora.getDay()] + " " + ahora.getDate() + " de " + mesesL[ahora.getMonth()] + " de " + ahora.getFullYear());
  const hora = String(ahora.getHours()).padStart(2, "0") + ":"
    + String(ahora.getMinutes()).padStart(2, "0");
  const lugar = info.ciudad ? (info.ciudad + (info.pais ? ", " + info.pais : "")) : "";

  const hh = ahora.getHours();
  const isNight = hh < 7 || hh >= 20;

  return (
    <div style={{
      background: "var(--wine)", color: "#fff",
      fontFamily: "Helvetica,Arial,sans-serif", fontSize: esMobile ? 11 : 12,
      padding: esMobile ? "6px 10px" : "7px 18px",
      display: "flex", justifyContent: "center",
      alignItems: "center", gap: esMobile ? 6 : 14,
      flexWrap: "nowrap", letterSpacing: ".3px",
      whiteSpace: "nowrap", overflow: "hidden"
    }}>
      <span>{fecha}{!esMobile ? (" · " + hora) : ""}</span>
      {lugar && <span style={{ opacity: .85 }}>· {lugar}</span>}
      {(info.temp !== null || info.code !== null) && (
        <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
          ·
          {info.code !== null && <ClimaIcon code={info.code} isNight={isNight} />}
          {info.temp !== null && <span>{info.temp}°</span>}
        </span>
      )}
    </div>
  );
}

// Íconos para el footer
const IcoMail = () => <svg viewBox="0 0 24 24" width="20" height="20" fill="none"
  stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
  <polyline points="22,6 12,13 2,6"/></svg>;
const IcoBell = () => <svg viewBox="0 0 24 24" width="20" height="20" fill="none"
  stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
  <path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>;
const IcoFbFoot = () => <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
  <path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"/></svg>;
const IcoXFoot = () => <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
  <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>;
const IcoIg = () => <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
  <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"/></svg>;
const IcoYt = () => <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
  <path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>;

function MiniSuscripcion({ ir }) {
  const [email, setEmail] = useState("");
  function entrar() {
    ir({ n: "pag", t: "Suscribirse", email: email });
  }
  return (
    <div className="mini-sus" style={{ marginTop: 10, display: "flex", gap: 6 }}>
      <input value={email} onChange={e => setEmail(e.target.value)}
        onKeyDown={e => { if (e.key === "Enter") entrar(); }}
        placeholder="Tu correo" type="email"
        style={{ flex: 1, padding: "8px 10px", fontSize: 13, border: 0,
          borderRadius: 4, fontFamily: "inherit", background: "#fff", color: "#222" }} />
      <button onClick={entrar}
        style={{ padding: "8px 12px", background: "var(--wine)", color: "#fff",
          border: 0, borderRadius: 4, fontSize: 13, cursor: "pointer",
          fontFamily: "Helvetica,Arial,sans-serif" }}>OK</button>
    </div>
  );
}

function PieSitio({ cfg, ir }) {
  const redes = [
    { url: cfg && cfg.red_facebook, ico: <IcoFbFoot />, nombre: "Facebook" },
    { url: cfg && cfg.red_x, ico: <IcoXFoot />, nombre: "X / Twitter" },
    { url: cfg && cfg.red_instagram, ico: <IcoIg />, nombre: "Instagram" },
    { url: cfg && cfg.red_youtube, ico: <IcoYt />, nombre: "YouTube" }
  ].filter(r => r.url);

  return (
    <footer>
      <div className="foot-grid">
        <div>
          <div className="foot-tt">CONTACTO</div>
          <a onClick={() => ir({ n: "pag", t: "Contacto" })}
            style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
            <IcoMail /> Escribir al director
          </a>
        </div>
        <div>
          <div className="foot-tt">SUSCRIBIRSE</div>
          <a onClick={() => ir({ n: "pag", t: "Suscribirse" })}
            style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
            <IcoBell /> Recibir novedades
          </a>
          <MiniSuscripcion ir={ir} />
        </div>
        <div>
          <div className="foot-tt">REDES</div>
          {redes.length > 0 ? (
            <div style={{ display: "flex", gap: 14, marginTop: 4 }}>
              {redes.map(r => (
                <a key={r.nombre} href={r.url} target="_blank" rel="noopener noreferrer"
                  title={r.nombre}
                  style={{ color: "#fff", opacity: .85, transition: "opacity .2s" }}
                  onMouseEnter={e => e.currentTarget.style.opacity = 1}
                  onMouseLeave={e => e.currentTarget.style.opacity = .85}>
                  {r.ico}
                </a>
              ))}
            </div>
          ) : (
            <div className="foot-x" style={{ fontSize: 12, opacity: .6 }}>
              Pronto en redes
            </div>
          )}
        </div>
      </div>
      <div className="foot-base">
        <div className="lg">ULTRAMONTANO</div>
        Revista de actualidad y pensamiento contrarrevolucionario · Dirigida por Dardo Juan Calderón
      </div>
    </footer>
  );
}

// ---------- ÍNDICE DE AUTORES ----------
function PaginaAutores({ arts, ir }) {
  // Agrupar artículos por autor (solo los que tengan al menos 1 publicado)
  const porAutor = {};
  arts.forEach(a => {
    if (a.slug === "presentacion") return;
    if (!a.autores || !a.autores.nombre) return;
    const k = a.autores.nombre;
    if (!porAutor[k]) porAutor[k] = { autor: a.autores, articulos: [] };
    porAutor[k].articulos.push(a);
  });
  const lista = Object.values(porAutor).sort((x, y) => x.autor.nombre.localeCompare(y.autor.nombre));

  return (
    <div className="wrap">
      <div className="sec">NUESTROS AUTORES</div>
      <div className="autores-grid">
        {lista.map(({ autor, articulos }) => {
          const bio = autor.bio || "";
          const bioCorta = bio.length > 160 ? bio.slice(0, 160).trim() + "…" : bio;
          return (
            <div key={autor.nombre} className="autor-card"
              onClick={() => ir(autor.nombre)}
              style={{ cursor: "pointer" }}>
              {autor.foto_url
                ? <img src={autor.foto_url} alt={autor.nombre} className="autor-foto" />
                : <div className="autor-foto autor-foto-vacia" />}
              <div className="autor-info">
                <div className="autor-nombre">{autor.nombre}</div>
                {bioCorta && <div className="autor-bio">{bioCorta}</div>}
                <div className="autor-meta">
                  {articulos.length} artículo{articulos.length !== 1 ? "s" : ""} publicado{articulos.length !== 1 ? "s" : ""}
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------- PÁGINA DE AUTOR INDIVIDUAL ----------
function PaginaAutor({ nombre, arts, abrir }) {
  const propios = arts.filter(a => a.autores && a.autores.nombre === nombre
    && a.slug !== "presentacion");
  const autor = propios[0] && propios[0].autores;

  // "Te puede interesar": un artículo por cada autor distinto (variado), excluyendo este autor
  const otros = arts.filter(a => a.autores && a.autores.nombre !== nombre
    && a.slug !== "presentacion");
  const vistos = {};
  const variado = [];
  for (const a of otros) {
    const nm = a.autores.nombre;
    if (!vistos[nm]) {
      vistos[nm] = true;
      variado.push(a);
      if (variado.length >= 6) break;
    }
  }

  return (
    <div className="wrap">
      {autor && (
        <div className="autor-cabecera">
          {autor.foto_url
            ? <img src={autor.foto_url} alt={autor.nombre} className="autor-foto-grande" />
            : <div className="autor-foto-grande autor-foto-vacia" />}
          <div>
            <h1 className="autor-titulo">{autor.nombre}</h1>
            {autor.bio && <div className="autor-bio-completa">{autor.bio}</div>}
            <div className="autor-meta-grande">
              {propios.length} artículo{propios.length !== 1 ? "s" : ""} publicado{propios.length !== 1 ? "s" : ""}
            </div>
          </div>
        </div>
      )}
      <div className="sec">ARTÍCULOS DE {(nombre || "").toUpperCase()}</div>
      <div className="grid2">
        {propios.map(a => <Card key={a.id} a={a} abrir={abrir} />)}
      </div>
      {variado.length > 0 && (
        <React.Fragment>
          <div className="sec">TAMBIÉN TE PUEDE INTERESAR</div>
          <div className="grid2">
            {variado.map(a => <Card key={"v" + a.id} a={a} abrir={abrir} />)}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

function App() {
  const [vista, setVista] = useState({ n: "home" });
  const [menu, setMenu] = useState(false);
  const [arts, setArts] = useState(null);
  const [cfg, setCfg] = useState({});

  // Registrar visita al sitio (una vez por carga de la app)
  useEffect(() => {
    if (!sb) return;
    // Esperamos 1s para que la barra del clima cargue ipinfo y guarde
    // en localStorage. Así reutilizamos esa data en lugar de pedir de nuevo.
    const t = setTimeout(async () => {
      try {
        const ua = (navigator.userAgent || "").toLowerCase();
        const esBot = /bot|crawl|spider|slurp|facebookexternalhit|whatsapp|preview|telegram/i.test(ua);

        // Detectar dispositivo a partir del user-agent (sin servicio externo)
        let dispositivo = "desktop";
        if (/ipad|tablet|playbook|silk|(android(?!.*mobile))/i.test(ua)) dispositivo = "tablet";
        else if (/mobile|iphone|ipod|android|blackberry|windows phone|opera mini|webos/i.test(ua)) dispositivo = "mobile";

        let sid = localStorage.getItem("ums_sid");
        if (!sid) {
          sid = Math.random().toString(36).slice(2) + Date.now().toString(36);
          localStorage.setItem("ums_sid", sid);
        }
        const hash = btoa((ua + "|" + sid).slice(0, 80)).slice(0, 32);

        // Obtener país, ciudad y región (caché en localStorage por 7 días)
        let pais = null, ciudad = null, region = null;
        try {
          const cache = localStorage.getItem("ums_geo");
          if (cache) {
            const obj = JSON.parse(cache);
            if (obj.ts && (Date.now() - obj.ts) < 7 * 24 * 3600 * 1000) {
              pais = obj.pais;
              ciudad = obj.ciudad;
              region = obj.region;
            }
          }
        } catch (e) { /* cache rota, ignorar */ }
        if (!pais && !esBot) {
          try {
            const r = await fetch("https://ipinfo.io/json?token=0f4469a755486a");
            const d = await r.json();
            if (d && d.country) {
              pais = d.country;
              ciudad = d.city || null;
              region = d.region || null;
              localStorage.setItem("ums_geo", JSON.stringify({
                pais, ciudad, region, ts: Date.now()
              }));
            }
          } catch (e) { /* sin geo si falla */ }
        }

        await sb.rpc("registrar_visita_sitio", {
          p_visitante_hash: hash,
          p_es_bot: esBot,
          p_dispositivo: dispositivo,
          p_pais: pais,
          p_ciudad: ciudad,
          p_region: region
        });
      } catch (e) { /* sin métricas si falla */ }
    }, 1000);
    return () => clearTimeout(t);
  }, []);

  useEffect(() => {
    if (!sb) { setArts([]); return; }
    (async () => {
      // Estrategia a prueba de balas: traer las 3 tablas por separado
      // y unirlas en código. Así no dependemos del sistema de joins de Supabase.
      const [resArt, resAut, resCat] = await Promise.all([
        sb.from("articulos").select("*").eq("publicado", true)
          .order("fecha", { ascending: false }),
        sb.from("autores").select("*"),
        sb.from("categorias").select("*")
      ]);
      const articulos = resArt.data || [];
      const autores = resAut.data || [];
      const categorias = resCat.data || [];
      // Indexar autores y categorías por id (como string, para evitar problemas de bigint)
      const mapaAut = {};
      autores.forEach(x => { mapaAut[String(x.id)] = x; });
      const mapaCat = {};
      categorias.forEach(x => { mapaCat[String(x.id)] = x; });
      // Adjuntar autor y categoría a cada artículo
      const a = articulos.map(art => ({
        ...art,
        autores: art.autor_id != null ? mapaAut[String(art.autor_id)] : null,
        categorias: art.categoria_id != null ? mapaCat[String(art.categoria_id)] : null
      }));
      // Log para diagnóstico (queda en la consola pero no molesta)
      if (articulos.length > 0 && autores.length > 0) {
        console.log("Diagnóstico:", {
          articulos: articulos.length,
          autores: autores.length,
          primer_articulo_autor_id: articulos[0].autor_id,
          primer_autor_id: autores[0].id,
          match: mapaAut[String(articulos[0].autor_id)] ? "OK" : "NO MATCH"
        });
      }
      setArts(a);
      try {
        const { data: c } = await sb.from("config").select("*");
        const o = {};
        (c || []).forEach(r => { o[r.clave] = r.valor; });
        setCfg(o);
        if (o.favicon) {
          let link = document.querySelector("link[rel~='icon']");
          if (!link) { link = document.createElement("link"); link.rel = "icon";
            document.head.appendChild(link); }
          link.href = o.favicon;
        }
      } catch (e) { /* config opcional */ }
      // Detectar ruta en URL: primero el path (URL limpia), luego el hash (compatibilidad)
      let path = (window.location.pathname || "/").replace(/^\/+/, "").replace(/\/+$/, "");
      if (!path) {
        path = (window.location.hash || "").replace(/^#\/?/, "");
      }
      if (path === "autores") {
        setVista({ n: "autores" });
      } else if (path.startsWith("autor/")) {
        const slugAutor = path.slice("autor/".length);
        const ar = (a || []).find(x => x.autores && slug(x.autores.nombre) === slugAutor);
        if (ar) setVista({ n: "autor", nombre: ar.autores.nombre });
      } else if (path) {
        const art = (a || []).find(x => x.slug === path);
        if (art) { setVista({ n: "art", art }); }
      }
    })();
  }, []);

  // Reaccionar al botón "atrás" / "adelante" del navegador
  useEffect(() => {
    function onPop() {
      const path = (window.location.pathname || "/").replace(/^\/+/, "").replace(/\/+$/, "");
      if (!path) {
        setVista({ n: "home" });
      } else if (path === "autores") {
        setVista({ n: "autores" });
      } else if (path.startsWith("autor/")) {
        // /autor/nombre-del-autor → buscar nombre original
        const slugAutor = path.slice("autor/".length);
        if (arts) {
          // buscamos un artículo cuyo autor tenga ese slug
          const a = arts.find(x => x.autores && slug(x.autores.nombre) === slugAutor);
          if (a) setVista({ n: "autor", nombre: a.autores.nombre });
          else setVista({ n: "home" });
        }
      } else if (arts) {
        const art = arts.find(x => x.slug === path);
        if (art) setVista({ n: "art", art });
        else setVista({ n: "home" });
      }
    }
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, [arts]);

  if (arts === null) return <div className="loading">Cargando…</div>;

  function abrir(art) {
    if (sb && art.id) sb.rpc("incrementar_lectura", { art_id: art.id });
    setVista({ n: "art", art });
    if (art.slug) {
      try { window.history.pushState({}, "", "/" + art.slug); } catch (e) {}
    }
    window.scrollTo(0, 0);
  }

  let cuerpo;
  if (vista.n === "art") {
    cuerpo = <Articulo art={vista.art} arts={arts} abrir={abrir} volver={() => {
      try { window.history.pushState({}, "", "/"); } catch (e) {}
      setVista({ n: "home" });
    }} />;
  } else if (vista.n === "quienes") {
    cuerpo = <Quienes arts={arts} cfg={cfg} />;
  } else if (vista.n === "pag") {
    if (vista.t === "Suscribirse") cuerpo = <Suscribirse emailInicial={vista.email} />;
    else if (vista.t === "Contacto") cuerpo = <Contacto />;
    else cuerpo = <div className="art"><h1>{vista.t}</h1><p>Sección en preparación.</p></div>;
  } else if (vista.n === "cat") {
    const f = arts.filter(a => a.categorias && a.categorias.slug === vista.slug);
    const esCorreo = vista.slug === "correo-de-lectores";
    cuerpo = (
      <div className="wrap">
        <div className="sec">{(vista.slug || "").toUpperCase().replace(/-/g, " ")}</div>
        {esCorreo && (
          <div style={{ marginBottom: 30 }}>
            <Contacto titulo="Escribí al director"
              intro="Tu mensaje llegará directo a la dirección de la revista. Las cartas seleccionadas se publican en esta sección." />
          </div>
        )}
        {esCorreo && f.length > 0 && <div className="sec">CARTAS PUBLICADAS</div>}
        <div className="grid2">{f.map(a => <Card key={a.id} a={a} abrir={abrir} />)}</div>
      </div>
    );
  } else if (vista.n === "autor") {
    cuerpo = <PaginaAutor nombre={vista.nombre} arts={arts} abrir={abrir} />;
  } else if (vista.n === "autores") {
    cuerpo = <PaginaAutores arts={arts} ir={nm => {
      setVista({ n: "autor", nombre: nm });
      try { window.history.pushState({}, "", "/autor/" + slug(nm)); } catch (e) {}
      window.scrollTo(0, 0);
    }} />;
  } else {
    cuerpo = <Home arts={arts} abrir={abrir}
      irAutor={nm => {
        setVista({ n: "autor", nombre: nm });
        try { window.history.pushState({}, "", "/autor/" + slug(nm)); } catch (e) {}
        window.scrollTo(0, 0);
      }}
      irAutores={() => {
        setVista({ n: "autores" });
        try { window.history.pushState({}, "", "/autores"); } catch (e) {}
        window.scrollTo(0, 0);
      }} />;
  }

  return (
    <React.Fragment>
      <BarraTop />
      <div className="header" onClick={() => {
          try { window.history.pushState({}, "", "/"); } catch (e) {}
          setVista({ n: "home" }); window.scrollTo(0, 0);
        }}
        style={{ cursor: "pointer", ...(cfg.header_fondo ? {
        backgroundImage: `linear-gradient(rgba(255,255,255,.86),rgba(255,255,255,.86)), url(${cfg.header_fondo})`,
        backgroundSize: "cover", backgroundPosition: "center"
      } : {}) }}>
        {cfg.logo_izquierda && (
          <img className="hlogo" src={cfg.logo_izquierda} alt="Logo" />
        )}
        <div className="htit">
          <div className="rev">R E V I S T A</div>
          <div className="name">ULTRAMONTANO</div>
        </div>
        {cfg.logo_derecha && (
          <img className="hvat" src={cfg.logo_derecha} alt="" />
        )}
      </div>
      <nav className={menu ? "open" : ""}>
        <div className="navtog" onClick={() => setMenu(!menu)}>
          <div className="navtog-logos">
            {cfg.logo_mobile_1 &&
              <img src={cfg.logo_mobile_1} alt="" className="nav-logo-mini" />}
            {cfg.logo_mobile_2 &&
              <img src={cfg.logo_mobile_2} alt="" className="nav-logo-mini" />}
          </div>
          <span className="bars"><span></span><span></span><span></span></span>
        </div>
        <div className="links">
          <a className={vista.n === "home" ? "act" : ""}
            onClick={() => { setVista({ n: "home" }); setMenu(false); }}>Inicio</a>
          <a onClick={() => { setVista({ n: "cat", slug: "opinion" }); setMenu(false); }}>Opinión</a>
          <a onClick={() => { setVista({ n: "cat", slug: "academico" }); setMenu(false); }}>Académico</a>
          <a onClick={() => { setVista({ n: "cat", slug: "novedades" }); setMenu(false); }}>Novedades</a>
          <a onClick={() => { setVista({ n: "cat", slug: "leido-para-usted" }); setMenu(false); }}>Leído para usted</a>
          <a onClick={() => { setVista({ n: "cat", slug: "correo-de-lectores" }); setMenu(false); }}>Correo de lectores</a>
          <a onClick={() => { setVista({ n: "pag", t: "Suscribirse" }); setMenu(false); }}>Suscribirse</a>
          <a onClick={() => { setVista({ n: "quienes" }); setMenu(false); }}>Quiénes somos</a>
          <a className="ingreso" href="admin.html"
            title="Acceso privado a la redacción">● Ingreso</a>
        </div>
      </nav>
      {cuerpo}
      <PieSitio cfg={cfg} ir={(v) => { setVista(v); window.scrollTo(0, 0); }} />
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById("app")).render(<App />);
