/* global React, BlogLogo, BlogNav, BlogFooter */
/* 85runtime - Blog Article Page
 *
 * Loaded after blog.jsx (see blog-article.html). Shared components
 * (BlogLogo, BlogNav, BlogFooter) and the React hook bindings come from
 * blog.jsx. Re-declaring them here causes a parse-time SyntaxError under
 * Babel-standalone and the page renders blank.
 */

// ── Date formatter (Slovak long form for article header)
const formatDateSkLong = (isoDate) => {
  if (!isoDate) return '';
  const d = new Date(isoDate);
  const months = [
    'januára','februára','marca','apríla','mája','júna',
    'júla','augusta','septembra','októbra','novembra','decembra',
  ];
  return `${d.getDate()}. ${months[d.getMonth()]} ${d.getFullYear()}`;
};

// ── Lexical richText renderer
// Renders Payload v3 Lexical JSON to React elements.
// Handles: root, paragraph, heading, text (bold/italic/code), list, listitem, linebreak.
const renderLexicalNode = (node, key) => {
  if (!node) return null;

  switch (node.type) {
    case 'root':
      return (
        <React.Fragment key={key}>
          {(node.children || []).map((child, i) => renderLexicalNode(child, i))}
        </React.Fragment>
      );

    case 'paragraph': {
      const children = (node.children || []).map((child, i) => renderLexicalNode(child, i));
      const isEmpty = children.every(c => c === null || c === '');
      if (isEmpty) return null;
      return <p key={key}>{children}</p>;
    }

    case 'heading': {
      const tag = node.tag || 'h2';
      const children = (node.children || []).map((child, i) => renderLexicalNode(child, i));
      if (tag === 'h1') return <h1 key={key}>{children}</h1>;
      if (tag === 'h3') return <h3 key={key}>{children}</h3>;
      if (tag === 'h4') return <h4 key={key}>{children}</h4>;
      return <h2 key={key}>{children}</h2>;
    }

    case 'text': {
      const text = node.text || '';
      if (!text) return null;
      const fmt = node.format || 0;
      if (fmt & 1) return <strong key={key}>{text}</strong>;
      if (fmt & 2) return <em key={key}>{text}</em>;
      if (fmt & 16) return <code key={key}>{text}</code>;
      return <React.Fragment key={key}>{text}</React.Fragment>;
    }

    case 'list': {
      const ListTag = node.listType === 'number' ? 'ol' : 'ul';
      return (
        <ListTag key={key}>
          {(node.children || []).map((child, i) => renderLexicalNode(child, i))}
        </ListTag>
      );
    }

    case 'listitem':
      return (
        <li key={key}>
          {(node.children || []).map((child, i) => renderLexicalNode(child, i))}
        </li>
      );

    case 'linebreak':
      return <br key={key} />;

    default:
      if (node.children) {
        return (
          <React.Fragment key={key}>
            {node.children.map((child, i) => renderLexicalNode(child, i))}
          </React.Fragment>
        );
      }
      return null;
  }
};

const LexicalContent = ({ content }) => {
  if (!content || !content.root) return null;
  return renderLexicalNode(content.root, 'root');
};

// ── Article visual banner.
//
// Two render modes:
//   1. Image mode: when Payload returns a real coverImage upload, render
//      the image full-bleed inside the banner. Uses the "hero" or "card"
//      size variant from Payload imageSizes when available.
//   2. Geometric mode: when no image is set, fall back to the gradient
//      class (blog-card-thumb--N) and render the matching THUMBS[N] SVG
//      from blog.jsx (shared global scope). This keeps the visual
//      vocabulary of the article hero in sync with the listing card,
//      and means a missing image never leaves an empty block.
//
// `image` is the resolved { url, alt } pair from pickCoverImage(), or null.
const ArticleVisualBanner = ({ image, variant }) => {
  if (image) {
    return (
      <div className="article-visual-banner article-visual-banner--photo">
        <img src={image.url} alt={image.alt} loading="lazy" decoding="async" />
      </div>
    );
  }
  const v = ((Number(variant) - 1 + 6) % 6) + 1;
  const Thumb = THUMBS[v - 1];
  return (
    <div className={`article-visual-banner blog-card-thumb--${v}`} aria-hidden="true">
      <Thumb />
    </div>
  );
};

// ── Reveal hook
const useArticleReveal = (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.08 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, deps);
};

// ── SEO head injection
const setMeta = (selector, attr, value) => {
  let el = document.querySelector(selector);
  if (!el) {
    el = document.createElement('meta');
    const [, kind, key] = selector.match(/^meta\[(name|property)="(.+)"\]$/) || [];
    if (!kind || !key) return;
    el.setAttribute(kind, key);
    document.head.appendChild(el);
  }
  el.setAttribute(attr, value);
};

const setCanonical = (href) => {
  let el = document.querySelector('link[rel="canonical"]');
  if (!el) {
    el = document.createElement('link');
    el.setAttribute('rel', 'canonical');
    document.head.appendChild(el);
  }
  el.setAttribute('href', href);
};

const setJsonLd = (id, data) => {
  let el = document.getElementById(id);
  if (!el) {
    el = document.createElement('script');
    el.type = 'application/ld+json';
    el.id = id;
    document.head.appendChild(el);
  }
  el.textContent = JSON.stringify(data);
};

const useSeoHead = (post) => {
  useEffect(() => {
    if (!post) return;
    const lang   = getLang();
    const title  = (post.seo && post.seo.metaTitle) || post.title;
    const desc   = (post.seo && post.seo.metaDescription) || post.excerpt || '';
    const slug   = post.slug;
    const url    = lang === 'en'
      ? `https://www.85runtime.sk/en/blog/${slug}`
      : `https://www.85runtime.sk/blog/${slug}`;
    const cover  = post.coverImage;
    const coverUrl = cover && (cover.sizes?.hero?.url || cover.sizes?.card?.url || cover.url);
    const imgUrl = coverUrl || 'https://www.85runtime.sk/og-image.png';
    const published = post.publishedAt || post.createdAt || null;
    const updated   = post.updatedAt   || published;

    document.title = `${title} - 85runtime`;
    setMeta('meta[name="description"]', 'content', desc);
    setCanonical(url);

    setMeta('meta[property="og:type"]',        'content', 'article');
    setMeta('meta[property="og:url"]',         'content', url);
    setMeta('meta[property="og:title"]',       'content', `${title} - 85runtime`);
    setMeta('meta[property="og:description"]', 'content', desc);
    setMeta('meta[property="og:image"]',       'content', imgUrl);
    if (published) setMeta('meta[property="article:published_time"]', 'content', published);
    if (updated)   setMeta('meta[property="article:modified_time"]',  'content', updated);

    setMeta('meta[name="twitter:title"]',       'content', `${title} - 85runtime`);
    setMeta('meta[name="twitter:description"]', 'content', desc);
    setMeta('meta[name="twitter:image"]',       'content', imgUrl);

    setJsonLd('ld-blogposting', {
      '@context': 'https://schema.org',
      '@type': 'BlogPosting',
      'headline': title,
      'description': desc,
      'mainEntityOfPage': { '@type': 'WebPage', '@id': url },
      'url': url,
      'image': imgUrl,
      'datePublished': published || undefined,
      'dateModified':  updated   || undefined,
      'author':    { '@type': 'Organization', 'name': '85runtime', 'url': 'https://www.85runtime.sk/' },
      'publisher': {
        '@type': 'Organization',
        'name': '85runtime',
        'logo': { '@type': 'ImageObject', 'url': 'https://www.85runtime.sk/logo.svg' }
      },
      'inLanguage': 'sk-SK'
    });
  }, [post]);
};

// ── 404 view
const NotFound = () => (
  <div className="article-page">
    <BlogNav />
    <div className="container" style={{ padding: '120px 32px', textAlign: 'center' }}>
      <div className="blog-label" style={{ justifyContent: 'center', marginBottom: 24 }}>404</div>
      <h2 style={{ fontSize: 'clamp(28px, 5vw, 48px)', marginTop: 16, marginBottom: 24 }}>Článok nebol nájdený</h2>
      <p style={{ marginTop: 16, color: 'var(--ink-2)' }}>
        <a href="/blog" className="article-back">
          <span className="article-back-arrow">←</span> Späť na blog
        </a>
      </p>
    </div>
    <BlogFooter />
  </div>
);

// ── Article Page
const ArticlePage = () => {
  const [post, setPost] = useState(undefined); // undefined = loading, null = not found
  const [error, setError] = useState(false);

  const lang = getLang();

  // Handle both /blog/:slug and /en/blog/:slug paths
  const slug = window.location.pathname
    .replace(/^\/en\/blog\//, '')
    .replace(/^\/blog\//, '')
    .replace(/\/$/, '') ||
    new URLSearchParams(window.location.search).get('slug');

  useEffect(() => {
    if (!slug) { setPost(null); return; }
    fetch(`/api/blog?action=post&slug=${encodeURIComponent(slug)}&lang=${lang}`)
      .then(r => {
        if (r.status === 404) { setPost(null); return null; }
        if (!r.ok) throw new Error(r.status);
        return r.json();
      })
      .then(data => { if (data !== null) setPost(data); })
      .catch((err) => { console.error('[blog-article] fetch failed:', slug, err); setError(true); });
  }, [slug, lang]);

  useSeoHead(post || null);
  useArticleReveal([post]);

  // Resolve translation slug for language switcher
  const translationObj = post && post.translation && typeof post.translation === 'object' ? post.translation : null;
  const translationSlug = translationObj ? translationObj.slug : undefined;

  // Loading
  if (post === undefined && !error) {
    return (
      <div className="article-page">
        <BlogNav lang={lang} translationSlug={translationSlug} />
        <div style={{ minHeight: '60vh' }} />
        <BlogFooter />
      </div>
    );
  }

  // Error
  if (error) {
    const errMsg = lang === 'en'
      ? '// Failed to load article. Try again later.'
      : '// Článok sa nepodarilo načítať. Skúste neskôr.';
    return (
      <div className="article-page">
        <BlogNav lang={lang} />
        <div className="container" style={{ padding: '120px 32px', textAlign: 'center' }}>
          <div style={{ color: 'var(--muted)', fontFamily: "'JetBrains Mono', monospace", fontSize: 13 }}>
            {errMsg}
          </div>
        </div>
        <BlogFooter />
      </div>
    );
  }

  // 404
  if (post === null) return <NotFound />;

  const catName = post.category && typeof post.category === 'object' ? post.category.name : (post.category || '');
  const dateStr = formatDateSkLong(post.publishedAt);
  const backLabel = lang === 'en' ? 'Back to blog' : 'Späť na blog';
  const ctaLabel = lang === 'en' ? 'Consultation' : 'Konzultácia';

  // Language switcher for article footer
  const translationHref = translationSlug
    ? (lang === 'sk' ? `/en/blog/${translationSlug}` : `/blog/${translationSlug}`)
    : null;

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

      <header className="article-header">
        <div className="container">
          <span className="legal-label">{catName}</span>
          <h1>{post.title}</h1>
          <div className="article-meta">
            {dateStr && <span>{dateStr}</span>}
            {dateStr && post.readTime && <span className="article-meta-sep">·</span>}
            {post.readTime && <span>{post.readTime}</span>}
            <span className="article-meta-sep">·</span>
            <span>85runtime</span>
          </div>
        </div>
      </header>

      <div className="article-visual-wrap">
        <div className="article-visual-inner">
          <ArticleVisualBanner image={pickCoverImage(post.coverImage, ['hero', 'card'])} variant={post.coverVariant} />
        </div>
      </div>

      <div className="article-body-wrap">
        <div className="container">
          <div className="article-prose reveal">
            {post.intro && <p className="article-intro">{post.intro}</p>}
            {post.content && <LexicalContent content={post.content} />}
          </div>
          {translationHref && (
            <div style={{ marginTop: 48, paddingTop: 24, borderTop: '1px solid var(--line)', display:'flex', alignItems:'center', gap: 12 }}>
              <span style={{ fontSize:13, color:'var(--ink-3)' }}>
                {lang === 'sk' ? 'Dostupné aj v angličtine:' : 'Also available in Slovak:'}
              </span>
              <a href={translationHref} style={{ fontSize:13, color:'var(--accent-2)', textDecoration:'none', padding:'4px 10px', border:'1px solid var(--accent-2)', borderRadius:4 }}>
                {lang === 'sk' ? '🇬🇧 Read in English' : '🇸🇰 Čítať po slovensky'}
              </a>
            </div>
          )}
        </div>
      </div>

      <div className="article-footer-wrap">
        <div className="article-footer-inner">
          <a href={getBlogBase(lang)} className="article-back">
            <span className="article-back-arrow">←</span>
            {backLabel}
          </a>
          <div className="article-cta-block">
            <a href="/#kontakt" className="btn btn-primary btn-sm">{ctaLabel} <span className="arr">→</span></a>
            <a href="/#kontakt" className="btn btn-ghost btn-sm">info@85runtime.sk</a>
          </div>
        </div>
      </div>

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

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.Fragment>
    <ArticlePage />
    <CookieConsent />
  </React.Fragment>
);
