/* global React */
/* 85runtime - Blog Listing Page */

const { useState, useEffect } = React;

// ── Language helpers (used by both blog.jsx and blog-article.jsx) ────────────
const getLang = () => window.location.pathname.startsWith('/en/') ? 'en' : 'sk';
const getBlogBase = (lang) => lang === 'en' ? '/en/blog' : '/blog';
const getBlogArticleUrl = (slug, lang) => lang === 'en' ? `/en/blog/${slug}` : `/blog/${slug}`;

// ── Logo (same as app.jsx)
const BlogLogo = () => (
  <a href="/" className="logo">
    <span className="logo-mark">
      <span className="logo-num">85</span>
      <span className="logo-slash">/</span>
    </span>
    <span className="logo-word">runtime</span>
  </a>
);

// ── Nav (Blog link is .active, language-aware)
const BlogNav = ({ lang: langProp, translationSlug } = {}) => {
  const lang = langProp !== undefined ? langProp : getLang();
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const fn = () => setScrolled(window.scrollY > 16);
    window.addEventListener('scroll', fn);
    return () => window.removeEventListener('scroll', fn);
  }, []);

  // Language toggle: swap between SK and EN. On article page, jump to translation if known.
  const skHref = translationSlug !== undefined
    ? (lang === 'en' ? `/blog/${translationSlug}` : window.location.pathname)
    : '/blog';
  const enHref = translationSlug !== undefined
    ? (lang === 'sk' ? `/en/blog/${translationSlug}` : window.location.pathname)
    : '/en/blog';

  return (
    <nav className={`nav ${scrolled ? 'scrolled' : ''}`}>
      <div className="nav-inner">
        <BlogLogo />
        <div className="nav-links">
          <a href="/#sluzby">{lang === 'en' ? 'Services' : 'Služby'}</a>
          <a href="/#showcases">Showcases</a>
          <a href={getBlogBase(lang)} className="active">Blog</a>
          <a href="/#o-nas">{lang === 'en' ? 'About' : 'O nás'}</a>
          <a href="/#kontakt">{lang === 'en' ? 'Contact' : 'Kontakt'}</a>
        </div>
        <div className="nav-cta">
          <a href="/#kontakt" className="btn btn-ghost btn-sm">info@85runtime.sk</a>
          <a href="/#kontakt" className="btn btn-primary btn-sm">
            {lang === 'en' ? 'Consultation' : 'Konzultácia'} <span className="arr">→</span>
          </a>
          <div className="blog-lang-toggle" style={{ display:'flex', gap:4, marginLeft:8 }}>
            <a href={skHref} className={`blog-lang-btn${lang === 'sk' ? ' active' : ''}`}
               style={{ fontSize:12, padding:'4px 8px', borderRadius:4, background: lang==='sk' ? 'var(--accent-1,#1a3a5c)' : 'transparent', color: lang==='sk' ? '#fff' : 'var(--ink-2)', textDecoration:'none', border:'1px solid var(--line,#dde)' }}>SK</a>
            <a href={enHref} className={`blog-lang-btn${lang === 'en' ? ' active' : ''}`}
               style={{ fontSize:12, padding:'4px 8px', borderRadius:4, background: lang==='en' ? 'var(--accent-1,#1a3a5c)' : 'transparent', color: lang==='en' ? '#fff' : 'var(--ink-2)', textDecoration:'none', border:'1px solid var(--line,#dde)' }}>EN</a>
          </div>
        </div>
      </div>
    </nav>
  );
};

// ── Footer
const BlogFooter = () => {
  function openCookies(e) {
    e.preventDefault();
    document.dispatchEvent(new CustomEvent('85rt:open-cookie-settings'));
  }
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-bottom">
          <span>© 2026 85runtime · runtime/85 :: v3.0</span>
          <div className="footer-legal-links">
            <a href="/cookie-policy">Zásady cookies</a>
            <a href="/terms-of-use">Podmienky používania</a>
            <button onClick={openCookies}>Nastavenia cookies</button>
          </div>
        </div>
      </div>
    </footer>
  );
};

// ── Date formatter (Slovak short form for cards)
const formatDateSk = (isoDate) => {
  if (!isoDate) return '';
  const d = new Date(isoDate);
  const months = ['JAN','FEB','MAR','APR','MÁJ','JÚN','JÚL','AUG','SEP','OKT','NOV','DEC'];
  return `${d.getDate()}. ${months[d.getMonth()]} ${d.getFullYear()}`;
};

// ── Media URL helpers (shared scope; used by blog.jsx + blog-article.jsx)
//
// Payload returns coverImage.url either as an absolute URL (when R2 storage
// is configured) or as a path relative to the CMS host (default Payload
// disk storage). Prepend the CMS base for the relative case so the browser
// fetches from cms.85runtime.sk, not from www.85runtime.sk.
const CMS_BASE = 'https://cms.85runtime.sk';
const resolveMediaUrl = (url) => {
  if (!url) return '';
  if (/^https?:\/\//i.test(url)) return url;
  return `${CMS_BASE}${url.startsWith('/') ? '' : '/'}${url}`;
};
// Pick the best available image variant from a Payload coverImage upload.
// For SVGs (vector) we always use the original URL. Payload's Sharp
// rasterizes them into PNGs when generating imageSizes variants, which
// would lose the crispness we're paying for. For raster formats we
// honor the requested size order (e.g. ['hero','card'] on the article
// page, ['card','thumbnail'] on the listing).
// Returns null when no image can be resolved. Callers must handle
// this and render the geometric fallback.
const pickCoverImage = (coverImage, sizeOrder = ['card', 'thumbnail']) => {
  if (!coverImage || typeof coverImage !== 'object') return null;
  if (coverImage.mimeType === 'image/svg+xml' && coverImage.url) {
    return { url: resolveMediaUrl(coverImage.url), alt: coverImage.alt || '' };
  }
  const sizes = coverImage.sizes || {};
  for (const s of sizeOrder) {
    if (sizes[s] && sizes[s].url) {
      return { url: resolveMediaUrl(sizes[s].url), alt: coverImage.alt || '' };
    }
  }
  if (coverImage.url) {
    return { url: resolveMediaUrl(coverImage.url), alt: coverImage.alt || '' };
  }
  return null;
};

// ── Mini Thumb SVGs ──────────────────────────────────────────────

// Thumb1: Network activation, dots grid with connecting lines
const Thumb1 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    <line x1="60" y1="40" x2="120" y2="40" stroke="currentColor" strokeWidth="1" opacity="0.3" />
    <line x1="120" y1="40" x2="180" y2="78" stroke="currentColor" strokeWidth="1" opacity="0.3" />
    <line x1="60" y1="78" x2="120" y2="40" stroke="currentColor" strokeWidth="1" opacity="0.3" />
    <line x1="120" y1="40" x2="120" y2="78" stroke="currentColor" strokeWidth="1" opacity="0.25" />
    <circle cx="60"  cy="40" r="7" fill="currentColor" opacity="0.6" />
    <circle cx="120" cy="40" r="7" fill="currentColor" opacity="0.6" />
    <circle cx="180" cy="40" r="7" fill="currentColor" opacity="0.6" />
    <circle cx="240" cy="40" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.25" />
    <circle cx="60"  cy="78" r="7" fill="currentColor" opacity="0.6" />
    <circle cx="120" cy="78" r="7" fill="currentColor" opacity="0.55" />
    <circle cx="180" cy="78" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.25" />
    <circle cx="240" cy="78" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.22" />
    <circle cx="60"  cy="116" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.22" />
    <circle cx="120" cy="116" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.22" />
    <circle cx="180" cy="116" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.22" />
    <circle cx="240" cy="116" r="5" stroke="currentColor" strokeWidth="1.5" opacity="0.22" />
  </svg>
);

// Thumb2: Decision matrix, 4 quadrants with check and X
const Thumb2 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    <rect x="60" y="20" width="90" height="58" fill="currentColor" opacity="0.08" rx="4" />
    <line x1="160" y1="16" x2="160" y2="140" stroke="currentColor" strokeWidth="2" opacity="0.4" />
    <line x1="56"  y1="78" x2="264" y2="78"  stroke="currentColor" strokeWidth="2" opacity="0.4" />
    <polyline points="82,47 92,57 114,35" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.65" />
    <line x1="186" y1="97" x2="206" y2="117" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" opacity="0.3" />
    <line x1="206" y1="97" x2="186" y2="117" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" opacity="0.3" />
    <rect x="170" y="22" width="84" height="50" fill="currentColor" opacity="0.03" rx="4" />
    <rect x="60"  y="84" width="90" height="50" fill="currentColor" opacity="0.03" rx="4" />
    <rect x="170" y="84" width="84" height="50" fill="currentColor" opacity="0.03" rx="4" />
  </svg>
);

// Thumb3: Three groups, assistant, workflow, agent
const Thumb3 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    <line x1="106" y1="18" x2="106" y2="130" stroke="currentColor" strokeWidth="1" opacity="0.2" strokeDasharray="4 3" />
    <line x1="212" y1="18" x2="212" y2="130" stroke="currentColor" strokeWidth="1" opacity="0.2" strokeDasharray="4 3" />
    <circle cx="53" cy="72" r="14" fill="currentColor" opacity="0.5" />
    <line x1="148" y1="50" x2="130" y2="90" stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <line x1="148" y1="50" x2="170" y2="90" stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <line x1="130" y1="90" x2="170" y2="90" stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <circle cx="148" cy="50" r="7" fill="currentColor" opacity="0.55" />
    <circle cx="130" cy="90" r="7" fill="currentColor" opacity="0.45" />
    <circle cx="170" cy="90" r="7" fill="currentColor" opacity="0.45" />
    <line x1="260" y1="44" x2="242" y2="62" stroke="currentColor" strokeWidth="1" opacity="0.3" />
    <line x1="260" y1="44" x2="278" y2="62" stroke="currentColor" strokeWidth="1" opacity="0.3" />
    <line x1="242" y1="62" x2="252" y2="82" stroke="currentColor" strokeWidth="1" opacity="0.28" />
    <line x1="278" y1="62" x2="268" y2="82" stroke="currentColor" strokeWidth="1" opacity="0.28" />
    <line x1="252" y1="82" x2="268" y2="82" stroke="currentColor" strokeWidth="1" opacity="0.28" />
    <line x1="260" y1="44" x2="260" y2="100" stroke="currentColor" strokeWidth="1" opacity="0.2" />
    <circle cx="260" cy="44"  r="6" fill="currentColor" opacity="0.55" />
    <circle cx="242" cy="62"  r="5" fill="currentColor" opacity="0.45" />
    <circle cx="278" cy="62"  r="5" fill="currentColor" opacity="0.45" />
    <circle cx="252" cy="82"  r="5" fill="currentColor" opacity="0.4" />
    <circle cx="268" cy="82"  r="5" fill="currentColor" opacity="0.4" />
    <circle cx="260" cy="100" r="4" fill="currentColor" opacity="0.35" />
    <text x="53"  y="118" textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="currentColor" opacity="0.5">A</text>
    <text x="150" y="118" textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="currentColor" opacity="0.5">W</text>
    <text x="260" y="118" textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="currentColor" opacity="0.5">AG</text>
  </svg>
);

// Thumb4: Content engine, three boxes with arrows
const Thumb4 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    <rect x="24" y="48" width="72" height="60" rx="8" stroke="currentColor" strokeWidth="1.5" opacity="0.4" fill="currentColor" fillOpacity="0.04" />
    <rect x="124" y="48" width="72" height="60" rx="8" stroke="currentColor" strokeWidth="1.5" opacity="0.5" fill="currentColor" fillOpacity="0.07" />
    <rect x="224" y="48" width="72" height="60" rx="8" stroke="currentColor" strokeWidth="1.5" opacity="0.4" fill="currentColor" fillOpacity="0.04" />
    <line x1="97" y1="78" x2="121" y2="78" stroke="currentColor" strokeWidth="1.5" opacity="0.5" />
    <polyline points="116,73 122,78 116,83" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.5" />
    <line x1="197" y1="78" x2="221" y2="78" stroke="currentColor" strokeWidth="1.5" opacity="0.5" />
    <polyline points="216,73 222,78 216,83" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.5" />
    <line x1="44" y1="72" x2="76" y2="72" stroke="currentColor" strokeWidth="1.2" opacity="0.5" />
    <line x1="44" y1="80" x2="68" y2="80" stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <line x1="44" y1="88" x2="72" y2="88" stroke="currentColor" strokeWidth="1.2" opacity="0.3" />
    <circle cx="160" cy="78" r="14" stroke="currentColor" strokeWidth="1.5" opacity="0.4" />
    <circle cx="160" cy="78" r="6"  fill="currentColor" opacity="0.3" />
    <line x1="242" y1="72" x2="278" y2="72" stroke="currentColor" strokeWidth="1.2" opacity="0.5" />
    <line x1="242" y1="80" x2="270" y2="80" stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <line x1="242" y1="88" x2="265" y2="88" stroke="currentColor" strokeWidth="1.2" opacity="0.3" />
  </svg>
);

// Thumb5: 6 numbered squares in 3×2 grid
const Thumb5 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    {[0,1,2,3,4,5].map(i => {
      const col = i % 3;
      const row = Math.floor(i / 3);
      const x = 50 + col * 78;
      const y = 28 + row * 72;
      return (
        <g key={i}>
          <rect x={x} y={y} width="58" height="52" rx="8"
            stroke="currentColor" strokeWidth="1.5" opacity={0.35 + i * 0.04}
            fill="currentColor" fillOpacity={0.03 + i * 0.01} />
          <text x={x + 29} y={y + 30} textAnchor="middle" dominantBaseline="middle"
            fontFamily="JetBrains Mono, monospace" fontSize="14" fontWeight="500"
            fill="currentColor" opacity="0.5">
            {String(i + 1).padStart(2, '0')}
          </text>
        </g>
      );
    })}
  </svg>
);

// Thumb6: Network with broken/dashed connections and X marks on some nodes
const Thumb6 = () => (
  <svg viewBox="0 0 320 156" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
    <line x1="70"  y1="50"  x2="130" y2="78"  stroke="currentColor" strokeWidth="1.2" strokeDasharray="5 4" opacity="0.3" />
    <line x1="130" y1="78"  x2="200" y2="55"  stroke="currentColor" strokeWidth="1.2" opacity="0.35" />
    <line x1="200" y1="55"  x2="250" y2="100" stroke="currentColor" strokeWidth="1.2" strokeDasharray="5 4" opacity="0.28" />
    <line x1="130" y1="78"  x2="160" y2="118" stroke="currentColor" strokeWidth="1.2" opacity="0.25" />
    <line x1="70"  y1="50"  x2="100" y2="110" stroke="currentColor" strokeWidth="1.2" strokeDasharray="4 4" opacity="0.22" />
    <circle cx="70"  cy="50"  r="10" fill="currentColor" opacity="0.45" />
    <circle cx="130" cy="78"  r="10" fill="currentColor" opacity="0.5" />
    <circle cx="200" cy="55"  r="8"  stroke="currentColor" strokeWidth="1.5" opacity="0.3" />
    <circle cx="250" cy="100" r="8"  fill="currentColor" opacity="0.35" />
    <circle cx="160" cy="118" r="7"  stroke="currentColor" strokeWidth="1.5" opacity="0.25" />
    <circle cx="100" cy="110" r="7"  stroke="currentColor" strokeWidth="1.5" opacity="0.25" />
    <line x1="196" y1="51" x2="204" y2="59" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" opacity="0.5" />
    <line x1="204" y1="51" x2="196" y2="59" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" opacity="0.5" />
    <line x1="156" y1="114" x2="164" y2="122" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" opacity="0.4" />
    <line x1="164" y1="114" x2="156" y2="122" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" opacity="0.4" />
  </svg>
);

const THUMBS = [Thumb1, Thumb2, Thumb3, Thumb4, Thumb5, Thumb6];

// Reveal hook, re-runs when posts load
const useBlogReveal = (deps) => {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.10 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, deps);
};

// ── Blog Card
const BlogCard = ({ post, index, lang }) => {
  const cardLang = lang || getLang();
  const variant = post.coverVariant || ((index % 6) + 1);
  const image = pickCoverImage(post.coverImage, ['card', 'thumbnail']);
  const ThumbComponent = THUMBS[(variant - 1) % 6];
  const catName = post.category && typeof post.category === 'object' ? post.category.name : '';
  const meta = [formatDateSk(post.publishedAt), post.readTime].filter(Boolean).join(' · ');
  return (
    <a
      href={getBlogArticleUrl(post.slug, cardLang)}
      className="blog-card-v2 reveal"
      style={{ transitionDelay: `${(index % 3) * 0.07}s` }}
    >
      <div
        className={`blog-card-thumb blog-card-thumb--${variant}${image ? ' blog-card-thumb--photo' : ''}`}
        style={{ color: 'var(--accent-2)' }}
      >
        {image
          ? <img src={image.url} alt={image.alt} loading="lazy" decoding="async" />
          : <ThumbComponent />}
      </div>
      <div className="blog-card-body">
        <span className="cat">{catName}</span>
        <h4>{post.title}</h4>
        <p>{post.excerpt}</p>
        <span className="meta">{meta}</span>
        <span className="read-more">{cardLang === 'en' ? 'Read article →' : 'Čítať článok →'}</span>
      </div>
    </a>
  );
};

// ── Skeleton card shown while loading
const SkeletonCard = ({ index }) => (
  <div className="blog-card-v2" style={{ pointerEvents: 'none', opacity: 0.35 }}>
    <div className={`blog-card-thumb blog-card-thumb--${(index % 6) + 1}`} />
    <div className="blog-card-body" style={{ gap: 10 }}>
      <div style={{ height: 10, width: '40%', background: 'var(--line)', borderRadius: 4 }} />
      <div style={{ height: 18, width: '85%', background: 'var(--line)', borderRadius: 4 }} />
      <div style={{ height: 14, width: '70%', background: 'var(--line)', borderRadius: 4 }} />
      <div style={{ height: 10, width: '50%', background: 'var(--line)', borderRadius: 4, marginTop: 'auto' }} />
    </div>
  </div>
);

// ── Blog Listing Page
const BlogListingPage = () => {
  const lang = getLang();
  const [posts, setPosts] = useState(null);
  const [error, setError] = useState(false);

  useEffect(() => {
    fetch(`/api/blog?lang=${lang}`)
      .then(r => {
        if (!r.ok) throw new Error(r.status);
        return r.json();
      })
      .then(data => setPosts(data.docs || []))
      .catch(() => setError(true));
  }, [lang]);

  useBlogReveal([posts]);

  const count = posts
    ? (lang === 'en'
        ? `${String(posts.length).padStart(2, '0')} articles`
        : `${String(posts.length).padStart(2, '0')} článkov`)
    : null;

  const headerLabel = lang === 'en' ? '85runtime · Insights from practice' : '85runtime · Poznatky z praxe';
  const headerDesc = lang === 'en'
    ? 'We write about how AI, software and automation translate into real business practice. No generic AI hype. We focus on what has value for people who want to use technology thoughtfully.'
    : 'Píšeme o tom, ako sa AI, softvér a automatizácia premietajú do firemnej praxe. Žiadne genericky prerozprávané AI hype. Zameriavame sa na to, čo má hodnotu pre ľudí, ktorí chcú technológie používať s rozmyslom.';
  const errorMsg = lang === 'en' ? '// Failed to load articles. Try again later.' : '// Nepodarilo sa načítať články. Skúste neskôr.';

  return (
    <div className="blog-page">
      <BlogNav lang={lang} />

      <header className="blog-header">
        <div className="container">
          <div className="blog-header-inner">
            <div>
              <div className="blog-label">{headerLabel}</div>
              <h1>Blog</h1>
              {count && <div className="blog-header-count">{count}</div>}
            </div>
            <div>
              <p className="blog-header-desc">{headerDesc}</p>
            </div>
          </div>
        </div>
      </header>

      <div className="blog-listing">
        <div className="container">
          {!posts && !error && (
            <div className="blog-listing-grid">
              {[...Array(6)].map((_, i) => <SkeletonCard key={i} index={i} />)}
            </div>
          )}

          {error && (
            <div style={{ padding: '60px 0', color: 'var(--muted)', fontFamily: "'JetBrains Mono', monospace", fontSize: 13 }}>
              {errorMsg}
            </div>
          )}

          {posts && posts.length > 0 && (
            <div className="blog-listing-grid">
              {posts.map((post, index) => (
                <BlogCard key={post.id} post={post} index={index} lang={lang} />
              ))}
            </div>
          )}

          {posts && posts.length === 0 && (
            <div style={{ padding: '60px 0', color: 'var(--muted)', fontFamily: "'JetBrains Mono', monospace", fontSize: 13 }}>
              {lang === 'en' ? '// No articles yet.' : '// Zatiaľ žiadne články.'}
            </div>
          )}

          <div className="blog-listing-note">
            {lang === 'en'
              ? '// The 85runtime website runs on a custom content engine with AI workflows.'
              : '// Web 85runtime beží na vlastnom obsahovom engine s AI workflowmi.'}
          </div>
        </div>
      </div>

      <BlogFooter />
    </div>
  );
};

// Only render when on the listing page. blog-article.html also loads this file for
// shared components (BlogNav, BlogFooter, Thumbs), so we must not double-render.
const _path = window.location.pathname;
if (_path === '/blog' || _path === '/blog/' || _path === '/en/blog' || _path === '/en/blog/') {
  ReactDOM.createRoot(document.getElementById('root')).render(
    <React.Fragment>
      <BlogListingPage />
      <CookieConsent />
    </React.Fragment>
  );
}
