// Single post view — fetches /content/blog/<slug>.md, strips frontmatter,
// renders the markdown body with markdown-it (loaded via CDN in index.html).

const CANONICAL_ORIGIN = 'https://lorakszak.com';
const FRONTMATTER_RE = /^---\r?\n[\s\S]*?\r?\n---\r?\n([\s\S]*)$/;

const escapeHtml = (s) => s
  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
  .replace(/"/g, '&quot;').replace(/'/g, '&#39;');

const md = window.markdownit({
  html: false, linkify: true, typographer: true, breaks: false,
  highlight: (str, lang) => {
    const hljs = window.hljs;
    if (lang && hljs && hljs.getLanguage(lang)) {
      try {
        const out = hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
        return `<pre class="hljs"><code>${out}</code></pre>`;
      } catch (_) {}
    }
    return `<pre class="hljs"><code>${escapeHtml(str)}</code></pre>`;
  },
});

const sanitizeHashtag = (t) => t.replace(/[^a-z0-9]/gi, '');

const ShareButtons = ({ title, slug, excerpt, tags, T }) => {
  const [flash, setFlash] = React.useState(null);
  const url = `${window.location.origin}/blog/${slug}`;
  const enc = encodeURIComponent;
  const safeExcerpt = excerpt || '';
  const hashtags = (tags || []).slice(0, 3).map(sanitizeHashtag).filter(Boolean).join(',');

  const open = (href) => {
    window.open(href, '_blank', 'noopener,noreferrer');
  };

  const onShare = async () => {
    try {
      await navigator.clipboard.writeText(url);
      setFlash('COPIED');
      setTimeout(() => setFlash(null), 1100);
    } catch (_) { setFlash('FAIL'); setTimeout(() => setFlash(null), 1100); }
  };

  const xText = `${title} ${safeExcerpt}`;
  const xHref = `https://twitter.com/intent/tweet?text=${enc(xText)}&url=${enc(url)}` +
    (hashtags ? `&hashtags=${enc(hashtags)}` : '');

  // LinkedIn deprecated shareArticle prefill in 2024. The feed?shareActive=true&text=
  // endpoint prefills the composer with arbitrary text including the URL.
  const liText = `${title} ${safeExcerpt} ${url}`;
  const liHref = `https://www.linkedin.com/feed/?shareActive=true&mini=true&text=${enc(liText)}`;

  const thText = `${title} ${safeExcerpt} ${url}`;
  const thHref = `https://www.threads.net/intent/post?text=${enc(thText)}`;

  const item = { cursor: 'pointer', userSelect: 'none' };

  return (
    <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}>
      <span
        style={{ ...item, color: flash ? T.accent : T.fgDim, letterSpacing: '0.1em' }}
        onClick={onShare}
      >
        {flash || '↗ DIRECT SHARE'}
      </span>
      <span style={item} onClick={() => open(xHref)}>↗ X</span>
      <span style={item} onClick={() => open(liHref)}>↗ LI</span>
      <span style={item} onClick={() => open(thHref)}>↗ TH</span>
    </div>
  );
};

const PostPage = ({ slug, readingMode, setReadingMode }) => {
  const T = window.TOKENS;
  const [post, setPost] = React.useState(null);
  const [bodyHtml, setBodyHtml] = React.useState('');
  const [error, setError] = React.useState(null);

  React.useEffect(() => { window.scrollTo(0, 0); }, [slug]);

  // self-referential canonical link: declares lorakszak.com as the source of
  // truth so search engines credit this URL when the post is mirrored on
  // Medium / dev.to / LinkedIn / etc. (those mirrors must also point their
  // own canonical at this URL).
  React.useEffect(() => {
    if (!slug) return;
    let link = document.querySelector('link[rel="canonical"]');
    if (!link) {
      link = document.createElement('link');
      link.setAttribute('rel', 'canonical');
      document.head.appendChild(link);
    }
    link.setAttribute('href', `${CANONICAL_ORIGIN}/blog/${slug}`);
    return () => {
      const stale = document.querySelector('link[rel="canonical"]');
      if (stale) stale.remove();
    };
  }, [slug]);

  React.useEffect(() => {
    if (!slug) return;
    setPost(null);
    setBodyHtml('');
    setError(null);

    Promise.all([
      fetch('/content/blog/index.json', { cache: 'no-cache' }).then(r => {
        if (!r.ok) throw new Error(`index.json ${r.status}`);
        return r.json();
      }),
      fetch(`/content/blog/${slug}.md`, { cache: 'no-cache' }).then(r => {
        if (!r.ok) throw new Error(`post ${r.status}`);
        return r.text();
      }),
    ]).then(([posts, raw]) => {
      const found = posts.find(p => p.slug === slug);
      if (!found) {
        setError(`post not found: ${slug}`);
        return;
      }
      const m = raw.match(FRONTMATTER_RE);
      const body = m ? m[1] : raw;
      const rendered = md.render(body);
      const safe = window.DOMPurify.sanitize(rendered, { USE_PROFILES: { html: true } });
      setPost(found);
      setBodyHtml(safe);
    }).catch(e => setError(e.message));
  }, [slug]);

  if (error) {
    return (
      <div style={{
        minHeight: '100vh', position: 'relative', zIndex: 1,
        padding: '140px 40px 160px', maxWidth: 760, margin: '0 auto',
        fontFamily: T.mono, color: T.fg,
      }}>
        <div style={{ fontSize: 12, letterSpacing: '0.2em', color: T.danger }}>
          [ERROR] {error}
        </div>
        <button
          onClick={() => window.navigate('/blog')}
          style={{
            marginTop: 32,
            padding: '10px 20px', background: 'transparent',
            border: `1px solid ${T.fgGhost}`, color: T.fg,
            fontFamily: T.mono, fontSize: 11, letterSpacing: '0.2em',
            textTransform: 'uppercase', cursor: 'pointer',
          }}
        >← all posts</button>
      </div>
    );
  }

  if (!post) {
    return (
      <div style={{
        minHeight: '100vh', position: 'relative', zIndex: 1,
        padding: '140px 40px 160px', maxWidth: 760, margin: '0 auto',
        fontFamily: T.mono, color: T.fgGhost, fontSize: 12, letterSpacing: '0.3em',
      }}>
        LOADING…
      </div>
    );
  }

  return (
    <div style={{
      minHeight: '100vh', position: 'relative', zIndex: 1,
      padding: '140px 40px 160px',
      fontFamily: T.mono, color: T.fg,
    }}>
      <div style={{ maxWidth: 760, margin: '0 auto' }}>
        {/* breadcrumb */}
        <div style={{
          fontSize: 11, letterSpacing: '0.3em', color: T.fgGhost, marginBottom: 32,
          display: 'flex', gap: 8, alignItems: 'center',
        }}>
          <span onClick={() => window.navigate('/blog')} style={{ cursor: 'pointer', color: T.accent }}>
            ← /blog
          </span>
          <span>/</span>
          <span>{post.id}</span>
        </div>

        {/* meta */}
        <div style={{
          fontSize: 11, letterSpacing: '0.2em', color: T.fgDim, marginBottom: 16,
          display: 'flex', gap: 16, flexWrap: 'wrap',
        }}>
          <span>{post.date}</span>
          <span>·</span>
          <span>{post.readMin} MIN READ</span>
          <span>·</span>
          {post.tags.map(t => <span key={t} style={{ color: T.accent }}>#{t}</span>)}
        </div>

        {/* title */}
        <h1 style={{
          margin: 0, fontSize: 'clamp(36px, 5vw, 56px)', lineHeight: 1.05, fontWeight: 800,
          letterSpacing: '-0.03em',
        }}>
          {post.title}
        </h1>

        <div style={{
          marginTop: 32, marginBottom: 48, padding: '16px 0',
          borderTop: `1px solid ${T.fgFaint}`, borderBottom: `1px solid ${T.fgFaint}`,
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          fontSize: 11, letterSpacing: '0.2em', color: T.fgDim,
        }}>
          <span>by KAROL ROSZAK · @lorakszak</span>
          <div style={{ display: 'flex', gap: 18, alignItems: 'center', flexWrap: 'wrap' }}>
            <span
              onClick={() => setReadingMode(!readingMode)}
              title={readingMode ? 'background animation off' : 'disable background animation'}
              style={{
                cursor: 'pointer', userSelect: 'none', letterSpacing: '0.1em',
                color: readingMode ? T.accent : T.fgDim,
              }}
            >
              {readingMode ? '◉' : '○'} READING MODE
            </span>
            <ShareButtons
              title={post.title}
              slug={post.slug}
              excerpt={post.excerpt}
              tags={post.tags}
              T={T}
            />
          </div>
        </div>

        {/* body — markdown rendered by markdown-it, sanitized with DOMPurify.
            Styled via .post-body rules in index.html. */}
        <div className="post-body" dangerouslySetInnerHTML={{ __html: bodyHtml }} />

        {/* footer */}
        <div style={{
          marginTop: 96, paddingTop: 32, borderTop: `1px solid ${T.fgFaint}`,
          display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 16,
        }}>
          <div style={{ fontSize: 11, letterSpacing: '0.2em', color: T.fgDim }}>
            ↗ originally published at <span style={{ color: T.accent }}>lorakszak.com/blog/{post.slug}</span><br/>
            <span style={{ color: T.fgGhost }}>cross-posts on LinkedIn / Medium link here as canonical.</span>
          </div>
          <button
            onClick={() => window.navigate('/blog')}
            style={{
              padding: '10px 20px', background: 'transparent',
              border: `1px solid ${T.fgGhost}`, color: T.fg,
              fontFamily: T.mono, fontSize: 11, letterSpacing: '0.2em',
              textTransform: 'uppercase', cursor: 'pointer',
            }}
          >
            ← all posts
          </button>
        </div>
      </div>
    </div>
  );
};

window.PostPage = PostPage;
