---
import { createMarkdownProcessor } from '@astrojs/markdown-remark';
import BaseLayout from '../../layouts/BaseLayout.astro';
import TerminalWindow from '../../components/ui/TerminalWindow.astro';
import CommandPrompt from '../../components/ui/CommandPrompt.astro';
import ResponsiveImage from '../../components/ui/ResponsiveImage.astro';
import TableOfContents from '../../components/TableOfContents.astro';
import RelatedPosts from '../../components/RelatedPosts.astro';
import ReadingProgress from '../../components/ReadingProgress.astro';
import Lightbox from '../../components/Lightbox.astro';
import CodeCopyButton from '../../components/CodeCopyButton.astro';
import Comments from '../../components/Comments.astro';
import ParagraphComments from '../../components/ParagraphComments.astro';
import QRCode from 'qrcode';
import {
  apiClient,
  DEFAULT_SITE_SETTINGS,
  resolvePublicApiBaseUrl,
} from '../../lib/api/client';
import { formatReadTime, getI18n } from '../../lib/i18n';
import {
  buildArticleFaqs,
  buildArticleHighlights,
  buildArticlePreviewParagraphs,
  buildArticleSynopsis,
  compactJsonLd,
  resolvePostUpdatedAt,
} from '../../lib/seo';
import type { PopularPostHighlight } from '../../lib/types';
import {
  buildCategoryUrl,
  buildTagUrl,
  getAccentVars,
  getCategoryTheme,
  getPostTypeColor,
  getPostTypeTheme,
  getTagTheme,
  resolveFileRef,
} from '../../lib/utils';

export const prerender = false;

const { slug } = Astro.params;

let post = null;
let siteSettings = DEFAULT_SITE_SETTINGS;
const analyticsEndpoint = `${resolvePublicApiBaseUrl(Astro.url)}/analytics/content`;
let homeData: Awaited<ReturnType<typeof apiClient.getHomePageData>> | null = null;

const [postResult, siteSettingsResult, homeDataResult] = await Promise.allSettled([
  apiClient.getPostBySlug(slug ?? ''),
  apiClient.getSiteSettings(),
  apiClient.getHomePageData(),
]);

if (postResult.status === 'fulfilled') {
  post = postResult.value;
} else {
  console.error('API Error:', postResult.reason);
}

if (siteSettingsResult.status === 'fulfilled') {
  siteSettings = siteSettingsResult.value;
} else {
  console.error('Site settings API Error:', siteSettingsResult.reason);
}

if (homeDataResult.status === 'fulfilled') {
  homeData = homeDataResult.value;
  if (siteSettingsResult.status !== 'fulfilled') {
    siteSettings = homeData.siteSettings;
  }
} else {
  console.error('Home data API Error:', homeDataResult.reason);
}

if (!post) {
  return new Response(null, {
    status: postResult.status !== 'fulfilled' ? 503 : 404,
    headers: postResult.status !== 'fulfilled' ? { 'Retry-After': '120' } : undefined,
  });
}

if (slug && post.slug !== slug) {
  return Astro.redirect(`/articles/${post.slug}`, 301);
}

const typeColor = getPostTypeColor(post.type || 'article');
const typeTheme = getPostTypeTheme(post.type || 'article');
const categoryTheme = getCategoryTheme(post.category);
const contentText = post.content || post.description || '';
const wordCount = contentText.length;
const readTimeMinutes = Math.ceil(wordCount / 300);
const { locale, t } = getI18n(Astro);
const isEnglish = locale.startsWith('en');
const articleMarkdown = contentText.replace(/^#\s+.+\r?\n+/, '');
const paragraphCommentsEnabled = siteSettings.comments.paragraphsEnabled;
const articleCopy = isEnglish
  ? {
      digestBadge: 'quick brief',
      digestKicker: 'reading preview',
      digestTitle: 'Read this first',
      digestDescription:
        'A short overview of the article so readers can quickly grasp the key points before sharing or saving it.',
      highlightsTitle: 'Key takeaways',
      faqTitle: 'Quick FAQ',
      sourceTitle: 'Page details',
      readTime: 'Read time',
      insightCount: 'Key points',
      faqCount: 'FAQ',
      updated: 'Updated',
      category: 'Category',
      canonical: 'Permalink',
      keywords: 'Keywords',
      copySummary: 'Copy digest',
      copySuccess: 'Digest copied',
      copyFailed: 'Copy failed',
      shareSummary: 'Share digest',
      shareSuccess: 'Share panel opened',
      shareFallback: 'Share text copied',
      shareFailed: 'Share failed',
      shareChannelsTitle: 'Share options',
      shareChannelsDescription:
        'Copy the overview or permalink, or continue sharing through the channels below.',
      shareToX: 'Share to X',
      shareToTelegram: 'Share to Telegram',
      shareToWeChat: 'WeChat scan',
      qrModalTitle: 'Scan with WeChat',
      qrModalDescription: 'Scan this QR code in WeChat to continue reading the article on mobile.',
      qrModalHint: 'When you want to send the article to someone else, copying the permalink below is usually the easiest option.',
      downloadQr: 'Download QR',
      downloadQrStarted: 'QR download started',
      qrOpened: 'WeChat QR ready',
      floatingToolsTitle: 'Quick actions',
      copyPermalinkSuccess: 'Permalink copied',
      copyPermalinkFailed: 'Permalink copy failed',
      toastSuccessTitle: 'Done',
      toastErrorTitle: 'Action failed',
      toastInfoTitle: 'Ready',
    }
  : {
      digestBadge: '文章导读',
      digestKicker: '阅读前速览',
      digestTitle: '先看重点',
      digestDescription: '先用几句话帮你抓住这篇文章的重点，方便快速浏览、收藏或转发。',
      highlightsTitle: '关键信息',
      faqTitle: '快速问答',
      sourceTitle: '页面信息',
      readTime: '阅读时长',
      insightCount: '重点条数',
      faqCount: '问答条数',
      updated: '最近更新',
      category: '归档分类',
      canonical: '固定链接',
      keywords: '关键词',
      copySummary: '复制摘要',
      copySuccess: '摘要已复制',
      copyFailed: '复制失败',
      shareSummary: '分享摘要',
      shareSuccess: '已打开分享面板',
      shareFallback: '分享文案已复制',
      shareFailed: '分享失败',
      shareChannelsTitle: '分享方式',
      shareChannelsDescription: '可以直接复制摘要、固定链接，或通过常用渠道继续转发。',
      shareToX: '分享到 X',
      shareToTelegram: '分享到 Telegram',
      shareToWeChat: '微信扫一扫',
      qrModalTitle: '微信扫一扫',
      qrModalDescription: '用微信扫一扫，就能在手机上继续阅读这篇文章。',
      qrModalHint: '发给别人时，优先复制固定链接，对方打开会更方便。',
      downloadQr: '下载二维码',
      downloadQrStarted: '二维码开始下载',
      qrOpened: '微信二维码已打开',
      floatingToolsTitle: '快捷操作',
      copyPermalinkSuccess: '固定链接已复制',
      copyPermalinkFailed: '固定链接复制失败',
      toastSuccessTitle: '操作完成',
      toastErrorTitle: '操作失败',
      toastInfoTitle: '已准备好',
    };

const markdownProcessor = await createMarkdownProcessor();
const renderedContent = await markdownProcessor.render(articleMarkdown);
const siteBaseUrl = (siteSettings.siteUrl || new URL(Astro.request.url).origin).replace(/\/$/, '');
const canonicalUrl = post.canonicalUrl || new URL(`/articles/${post.slug}`, siteBaseUrl).toString();
const ogImage = post.ogImage || `/og/${post.slug}.svg`;
const wechatShareQrEnabled = Boolean(siteSettings.seo.wechatShareQrEnabled);
const noindex = Boolean(post.noindex || post.visibility === 'unlisted');
const publishedAt = post.publishAt || post.createdAt || `${post.date}T00:00:00Z`;
const updatedAt = resolvePostUpdatedAt(post);
const updatedAtIso = new Date(updatedAt).toISOString();
const updatedAtLabel = Number.isNaN(new Date(updatedAt).valueOf())
  ? updatedAt
  : new Date(updatedAt).toLocaleDateString(locale, {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
    });
const articleSynopsis = buildArticleSynopsis(post, 220);
const articlePreviewParagraphs = buildArticlePreviewParagraphs(post, 3, 110);
const articleHighlights = buildArticleHighlights(post, 3);
const articleFaqs = buildArticleFaqs(post, {
  locale,
  summary: articleSynopsis,
  readTimeMinutes,
});
const digestStats = [
  {
    label: articleCopy.readTime,
    value: `${Math.max(readTimeMinutes, 1)}m`,
  },
  {
    label: articleCopy.insightCount,
    value: String(articleHighlights.length || 1),
  },
  {
    label: articleCopy.keywords,
    value: String(post.tags?.length || 0),
  },
];
const articleDigestClipboardText = [
  post.title,
  articleSynopsis,
  articleHighlights.length
    ? `${articleCopy.highlightsTitle}:\n${articleHighlights.map((item, index) => `${index + 1}. ${item}`).join('\n')}`
    : '',
  `${articleCopy.canonical}: ${canonicalUrl}`,
]
  .filter(Boolean)
  .join('\n\n');
const articleDigestShareText = [post.title, articleSynopsis, canonicalUrl].filter(Boolean).join('\n\n');
const articleShareTeaser = [post.title, articleHighlights[0] || articleSynopsis]
  .filter(Boolean)
  .join(' — ')
  .slice(0, 220);
const xShareUrl = `https://x.com/intent/tweet?text=${encodeURIComponent(articleShareTeaser)}&url=${encodeURIComponent(canonicalUrl)}`;
const telegramShareUrl = `https://t.me/share/url?url=${encodeURIComponent(canonicalUrl)}&text=${encodeURIComponent(articleShareTeaser)}`;
let wechatShareQrSvg = '';
let wechatShareQrPngDataUrl = '';
if (wechatShareQrEnabled) {
  try {
    wechatShareQrSvg = await QRCode.toString(canonicalUrl, {
      type: 'svg',
      margin: 1,
      width: 240,
      color: {
        dark: '#111827',
        light: '#ffffff',
      },
    });
    wechatShareQrPngDataUrl = await QRCode.toDataURL(canonicalUrl, {
      margin: 1,
      width: 420,
      color: {
        dark: '#111827',
        light: '#ffffff',
      },
    });
  } catch (error) {
    console.error('WeChat QR generation error:', error);
  }
}
const hotRelatedPosts = (homeData?.popularPosts ?? [])
  .filter((item): item is PopularPostHighlight & { post: NonNullable<PopularPostHighlight['post']> } => Boolean(item.post))
  .filter((item) => item.slug !== post.slug)
  .map((item) => {
    const sharedTags = item.post.tags.filter((tag) => post.tags.includes(tag));
    const sameCategory = item.post.category === post.category;
    const sameType = item.post.type === post.type;
    const relevance = (sameCategory ? 4 : 0) + sharedTags.length * 3 + (sameType ? 1 : 0);
    const popularityScore =
      item.pageViews + item.readCompletes * 2 + item.avgProgressPercent / 20;

    return {
      ...item,
      sharedTags,
      sameCategory,
      relevance,
      popularityScore,
      finalScore: relevance * 100 + popularityScore,
    };
  })
  .filter((item) => item.relevance > 0)
  .sort((left, right) => {
    return (
      right.finalScore - left.finalScore ||
      right.pageViews - left.pageViews ||
      right.readCompletes - left.readCompletes
    );
  })
  .slice(0, 3);
const articleJsonLd = {
  '@context': 'https://schema.org',
  '@type': post.type === 'article' ? 'BlogPosting' : 'Article',
  headline: post.title,
  description: post.description,
  abstract: articleSynopsis,
  image: [new URL(ogImage, siteBaseUrl).toString()],
  mainEntityOfPage: canonicalUrl,
  url: canonicalUrl,
  datePublished: publishedAt,
  dateModified: updatedAtIso,
  author: {
    '@type': 'Person',
    name: siteSettings.ownerName,
  },
  publisher: {
    '@type': 'Organization',
    name: siteSettings.siteName,
    logo: siteSettings.ownerAvatarUrl
      ? {
          '@type': 'ImageObject',
          url: siteSettings.ownerAvatarUrl,
        }
      : undefined,
  },
  articleSection: post.category,
  keywords: post.tags,
  inLanguage: locale,
  isAccessibleForFree: true,
  wordCount,
  timeRequired: `PT${Math.max(readTimeMinutes, 1)}M`,
};
const faqJsonLd = articleFaqs.length
  ? {
      '@context': 'https://schema.org',
      '@type': 'FAQPage',
      mainEntity: articleFaqs.map((item) => ({
        '@type': 'Question',
        name: item.question,
        acceptedAnswer: {
          '@type': 'Answer',
          text: item.answer,
        },
      })),
    }
  : undefined;
const breadcrumbJsonLd = {
  '@context': 'https://schema.org',
  '@type': 'BreadcrumbList',
  itemListElement: [
    {
      '@type': 'ListItem',
      position: 1,
      name: siteSettings.siteName,
      item: siteBaseUrl,
    },
    {
      '@type': 'ListItem',
      position: 2,
      name: 'Articles',
      item: new URL('/articles', siteBaseUrl).toString(),
    },
    {
      '@type': 'ListItem',
      position: 3,
      name: post.title,
      item: canonicalUrl,
    },
  ],
};
---

<BaseLayout
  title={post.title}
  description={post.description}
  siteSettings={siteSettings}
  canonical={canonicalUrl}
  noindex={noindex}
  ogImage={ogImage}
  ogType="article"
  twitterCard="summary_large_image"
  jsonLd={compactJsonLd([articleJsonLd, breadcrumbJsonLd, faqJsonLd])}
>
  <Fragment slot="head">
    <meta property="article:published_time" content={publishedAt} />
    <meta property="article:modified_time" content={updatedAtIso} />
    <meta property="article:section" content={post.category} />
    {post.tags.map((tag) => <meta property="article:tag" content={tag} />)}
  </Fragment>
  <ReadingProgress />
  <Lightbox />
  <CodeCopyButton />

  <div class="mx-auto max-w-[1660px] px-4 py-8 sm:px-6 lg:px-8" data-article-slug={post.slug}>
    <div class="grid gap-8 xl:grid-cols-[minmax(0,1fr)_17.5rem] 2xl:grid-cols-[minmax(0,1fr)_18.5rem]">
      <div class="min-w-0 flex-1">
        <TerminalWindow title={`~/articles/${post.slug}`} class="w-full">
          <div class="px-4 pb-2">
            <div class="terminal-panel ml-4 mt-4 space-y-5">
              <div class="flex flex-wrap items-start justify-between gap-4">
                <div class="space-y-4">
                  <a href="/articles" class="terminal-link-arrow">
                    <i class="fas fa-arrow-left"></i>
                    <span>{t('article.backToArticles')}</span>
                  </a>

                  <div class="flex flex-wrap items-center gap-2">
                    <span class="terminal-kicker">
                      <i class="fas fa-file-code"></i>
                      {t('article.documentSession')}
                    </span>
                    <span class="terminal-chip terminal-chip--accent" style={getAccentVars(typeTheme)}>
                      <span class="h-2.5 w-2.5 rounded-full" style={`background-color: ${typeColor}`}></span>
                      {post.type === 'article' ? t('common.article') : t('common.tweet')}
                    </span>
                    <a
                      href={buildCategoryUrl(post.category)}
                      class="terminal-chip terminal-chip--accent"
                      style={getAccentVars(categoryTheme)}
                    >
                      <i class="fas fa-folder-tree"></i>
                      {post.category}
                    </a>
                  </div>
                </div>

                <div class="flex flex-wrap gap-2">
                  <span class="terminal-stat-pill">
                    <i class="far fa-calendar text-[var(--primary)]"></i>
                    {post.date}
                  </span>
                  <span class="terminal-stat-pill">
                    <i class="far fa-clock text-[var(--primary)]"></i>
                    {formatReadTime(locale, readTimeMinutes, t)}
                  </span>
                  <span class="terminal-stat-pill">
                    <i class="fas fa-font text-[var(--primary)]"></i>
                    {t('common.characters', { count: wordCount })}
                  </span>
                </div>
              </div>

              <div class="space-y-3">
                <h1 class="text-3xl font-bold tracking-tight text-[var(--title-color)] sm:text-4xl">{post.title}</h1>
                <p class="max-w-3xl text-base leading-8 text-[var(--text-secondary)]">{post.description}</p>
              </div>

              <section class="grid items-start gap-5 xl:grid-cols-[minmax(0,1.62fr)_minmax(16.5rem,0.78fr)] 2xl:grid-cols-[minmax(0,1.8fr)_minmax(17rem,0.82fr)]">
                <div class="relative overflow-hidden rounded-[28px] border border-[var(--border-color)] bg-[linear-gradient(135deg,rgba(var(--primary-rgb),0.12),rgba(var(--secondary-rgb),0.05)_46%,rgba(var(--bg-rgb),0.92))] p-5 sm:p-6">
                  <div class="absolute inset-y-0 left-0 w-1 rounded-full bg-[var(--primary)]/80"></div>
                  <div class="absolute right-0 top-0 h-36 w-36 rounded-full bg-[var(--primary)]/10 blur-3xl"></div>
                  <div class="absolute bottom-0 right-10 h-24 w-24 rounded-full bg-[var(--secondary)]/10 blur-3xl"></div>
                  <div class="relative space-y-4">
                    <div class="flex flex-wrap items-center gap-2">
                      <span class="inline-flex items-center gap-2 rounded-full border border-[var(--primary)]/20 bg-[var(--primary)]/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.24em] text-[var(--primary)]">
                        <i class="fas fa-sparkles text-[10px]"></i>
                        {articleCopy.digestBadge}
                      </span>
                      <span class="terminal-kicker">
                        <i class="fas fa-book-open"></i>
                        {articleCopy.digestKicker}
                      </span>
                    </div>

                    <div class="space-y-3">
                      <h2 class="text-xl font-semibold text-[var(--title-color)] sm:text-2xl">{articleCopy.digestTitle}</h2>
                      <p class="max-w-3xl text-sm leading-7 text-[var(--text-secondary)]">{articleCopy.digestDescription}</p>
                    </div>

                    <div class="rounded-[24px] border border-[var(--border-color)]/70 bg-[var(--terminal-bg)]/88 p-5 shadow-[0_20px_55px_rgba(15,23,42,0.08)]">
                      <div class="space-y-3">
                        {articlePreviewParagraphs.map((paragraph) => (
                          <p class="text-[15px] leading-8 text-[var(--title-color)]">{paragraph}</p>
                        ))}
                      </div>
                    </div>

                    <div class="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
                      <div class="flex flex-wrap gap-2">
                        <button
                          type="button"
                          class="terminal-action-button"
                          data-article-digest-copy
                          data-default-label={articleCopy.copySummary}
                          data-success-label={articleCopy.copySuccess}
                          data-failed-label={articleCopy.copyFailed}
                        >
                          <i class="fas fa-copy"></i>
                          <span>{articleCopy.copySummary}</span>
                        </button>
                        <button
                          type="button"
                          class="terminal-action-button terminal-action-button-primary"
                          data-article-digest-share
                          data-default-label={articleCopy.shareSummary}
                          data-success-label={articleCopy.shareSuccess}
                          data-fallback-label={articleCopy.shareFallback}
                          data-failed-label={articleCopy.shareFailed}
                        >
                          <i class="fas fa-share-nodes"></i>
                          <span>{articleCopy.shareSummary}</span>
                        </button>
                      </div>
                      <p
                        class="min-h-[1.25rem] text-xs text-[var(--text-tertiary)]"
                        data-article-digest-status
                        aria-live="polite"
                      ></p>
                    </div>

                    <div class="grid gap-3 xl:grid-cols-[minmax(0,1.18fr)_minmax(13rem,0.82fr)]">
                      <div class="rounded-2xl border border-[var(--border-color)]/70 bg-[var(--terminal-bg)]/72 px-4 py-3">
                        <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                          <div class="space-y-1">
                            <p class="text-[11px] font-semibold uppercase tracking-[0.22em] text-[var(--text-tertiary)]">
                              {articleCopy.shareChannelsTitle}
                            </p>
                            <p class="text-xs leading-6 text-[var(--text-secondary)]">
                              {articleCopy.shareChannelsDescription}
                            </p>
                          </div>
                          <div class="flex flex-wrap gap-2">
                            <a
                              href={xShareUrl}
                              target="_blank"
                              rel="noopener noreferrer nofollow"
                              class="terminal-action-button"
                              data-article-share-link
                            >
                              <i class="fab fa-twitter"></i>
                              <span>{articleCopy.shareToX}</span>
                            </a>
                            <a
                              href={telegramShareUrl}
                              target="_blank"
                              rel="noopener noreferrer nofollow"
                              class="terminal-action-button"
                              data-article-share-link
                            >
                              <i class="fab fa-telegram-plane"></i>
                              <span>{articleCopy.shareToTelegram}</span>
                            </a>
                            {wechatShareQrEnabled && wechatShareQrSvg && (
                              <button
                                type="button"
                                class="terminal-action-button"
                                data-article-wechat-qr-open
                              >
                                <i class="fab fa-weixin"></i>
                                <span>{articleCopy.shareToWeChat}</span>
                              </button>
                            )}
                          </div>
                        </div>
                      </div>

                      <div class="grid gap-3 sm:grid-cols-3 xl:grid-cols-1">
                        {digestStats.map((item) => (
                          <div class="rounded-2xl border border-[var(--border-color)]/75 bg-[var(--terminal-bg)]/78 px-4 py-3">
                            <div class="text-[11px] uppercase tracking-[0.2em] text-[var(--text-tertiary)]">{item.label}</div>
                            <div class="mt-2 text-2xl font-semibold text-[var(--title-color)]">{item.value}</div>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                </div>

                <div class="space-y-4">
                  <div class="rounded-[24px] border border-[var(--border-color)]/75 bg-[var(--terminal-bg)]/86 p-5 shadow-[0_18px_42px_rgba(15,23,42,0.06)]">
                    <h3 class="text-sm font-semibold uppercase tracking-[0.22em] text-[var(--text-tertiary)]">
                      {articleCopy.sourceTitle}
                    </h3>
                    <dl class="mt-4 space-y-4 text-sm">
                      <div>
                        <dt class="text-[var(--text-tertiary)]">{articleCopy.updated}</dt>
                        <dd class="mt-1 text-[var(--title-color)]">{updatedAtLabel}</dd>
                      </div>
                      <div>
                        <dt class="text-[var(--text-tertiary)]">{articleCopy.category}</dt>
                        <dd class="mt-1">
                          <a
                            href={buildCategoryUrl(post.category)}
                            class="text-[var(--title-color)] underline decoration-dotted underline-offset-4 hover:text-[var(--primary)]"
                          >
                            {post.category}
                          </a>
                        </dd>
                      </div>
                      <div>
                        <dt class="text-[var(--text-tertiary)]">{articleCopy.canonical}</dt>
                        <dd class="mt-1 break-all font-mono text-xs leading-6 text-[var(--title-color)]">{canonicalUrl}</dd>
                      </div>
                      <div>
                        <dt class="text-[var(--text-tertiary)]">{articleCopy.keywords}</dt>
                        <dd class="mt-2 flex flex-wrap gap-2">
                          {post.tags.map((tag) => (
                            <a
                              href={buildTagUrl(tag)}
                              class="terminal-chip terminal-chip--accent px-2.5 py-1 text-xs"
                              style={getAccentVars(getTagTheme(tag))}
                            >
                              <i class="fas fa-hashtag text-[10px]"></i>
                              {tag}
                            </a>
                          ))}
                        </dd>
                      </div>
                    </dl>
                  </div>

                  {articleHighlights.length > 0 && (
                    <div class="rounded-[24px] border border-[var(--border-color)]/75 bg-[var(--terminal-bg)]/86 p-5 shadow-[0_18px_42px_rgba(15,23,42,0.06)]">
                      <h3 class="text-sm font-semibold uppercase tracking-[0.22em] text-[var(--text-tertiary)]">
                        {articleCopy.highlightsTitle}
                      </h3>
                      <div class="mt-4 space-y-3">
                        {articleHighlights.map((item, index) => (
                          <div class="flex items-start gap-3 rounded-2xl border border-[var(--border-color)]/80 bg-[var(--bg)]/58 px-4 py-3">
                            <span class="mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--primary)]/10 text-[11px] font-semibold text-[var(--primary)]">
                              {index + 1}
                            </span>
                            <p class="text-sm leading-7 text-[var(--title-color)]">{item}</p>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}
                </div>
              </section>

              {post.tags?.length > 0 && (
                <div class="flex flex-wrap gap-2">
                  {post.tags.map(tag => (
                    <a
                      href={buildTagUrl(tag)}
                      class="terminal-filter"
                      style={getAccentVars(getTagTheme(tag))}
                    >
                      <i class="fas fa-hashtag"></i>
                      <span>{tag}</span>
                    </a>
                  ))}
                </div>
              )}
            </div>
          </div>

          <div class="px-4 pb-2">
            <CommandPrompt command={`preview article --slug ${post.slug}`} />

            <div class="ml-4 mt-4 space-y-6">
              {post.image && (
                <div class="terminal-panel-muted overflow-hidden">
                  <ResponsiveImage
                    src={resolveFileRef(post.image)}
                    alt={post.title}
                    pictureClass="block"
                    imgClass="w-full h-auto rounded-xl border border-[var(--border-color)] cursor-zoom-in"
                    widths={[640, 960, 1280, 1600, 1920]}
                    sizes="(min-width: 1280px) 60rem, 100vw"
                    loading="eager"
                    fetchpriority="high"
                    lightbox={true}
                  />
                </div>
              )}

              {post.images && post.images.length > 0 && (
                <div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
                  {post.images.map((image, index) => (
                    <div class="terminal-panel-muted overflow-hidden">
                      <ResponsiveImage
                        src={resolveFileRef(image)}
                        alt={`${post.title} 图片 ${index + 1}`}
                        pictureClass="block h-full w-full"
                        imgClass="h-full w-full rounded-xl border border-[var(--border-color)] object-cover cursor-zoom-in"
                        widths={[480, 720, 960, 1280]}
                        sizes="(min-width: 1280px) 30vw, (min-width: 640px) 45vw, 100vw"
                        lightbox={true}
                      />
                    </div>
                  ))}
                </div>
              )}

              {paragraphCommentsEnabled && (
                <ParagraphComments postSlug={post.slug} class="mb-4" siteSettings={siteSettings} />
              )}

              <div class="terminal-document article-content" set:html={renderedContent.code}></div>
            </div>
          </div>

          <div class="px-4 py-6">
            <div class="terminal-panel-muted ml-4 mt-4 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-end">
              <div class="flex flex-wrap gap-2">
                <a href="/articles" class="terminal-action-button">
                  <i class="fas fa-list"></i>
                  <span>{t('common.backToIndex')}</span>
                </a>
                <button
                  class="terminal-action-button terminal-action-button-primary"
                  data-article-permalink-copy
                  data-default-label={t('common.copyPermalink')}
                  data-success-label={articleCopy.copyPermalinkSuccess}
                  data-failed-label={articleCopy.copyPermalinkFailed}
                >
                  <i class="fas fa-link"></i>
                  <span>{t('common.copyPermalink')}</span>
                </button>
              </div>
            </div>
          </div>
        </TerminalWindow>

        <RelatedPosts
          currentSlug={post.slug}
          currentCategory={post.category}
          currentTags={post.tags}
        />

        {hotRelatedPosts.length > 0 && (
          <section class="terminal-panel mt-8">
            <div class="space-y-5">
              <div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
                <div class="space-y-3">
                  <span class="terminal-kicker">
                    <i class="fas fa-fire"></i>
                    {t('relatedPosts.hotKicker')}
                  </span>
                  <div class="terminal-section-title">
                    <span class="terminal-section-icon">
                      <i class="fas fa-chart-line"></i>
                    </span>
                    <div>
                      <h3 class="text-xl font-semibold text-[var(--title-color)]">{t('relatedPosts.hotTitle')}</h3>
                      <p class="text-sm text-[var(--text-secondary)]">
                        {t('relatedPosts.hotDescription')}
                      </p>
                    </div>
                  </div>
                </div>

                <span class="terminal-stat-pill">
                  <i class="fas fa-signal text-[var(--primary)]"></i>
                  {t('relatedPosts.linked', { count: hotRelatedPosts.length })}
                </span>
              </div>

              <div class="grid gap-4 md:grid-cols-3">
                {hotRelatedPosts.map((item) => (
                  <a
                    href={`/articles/${item.slug}`}
                    class="terminal-panel-muted terminal-panel-accent terminal-interactive-card group flex h-full flex-col gap-4 p-4"
                    style={getAccentVars(getPostTypeTheme(item.post.type))}
                  >
                    {item.post.image ? (
                      <div class="overflow-hidden rounded-xl border border-[var(--border-color)]">
                        <ResponsiveImage
                          src={resolveFileRef(item.post.image)}
                          alt={item.post.title}
                          pictureClass="block"
                          imgClass="aspect-[16/9] w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]"
                          widths={[320, 480, 640, 960]}
                          sizes="(min-width: 1280px) 18rem, (min-width: 768px) 30vw, 100vw"
                        />
                      </div>
                    ) : null}

                    <div class="space-y-3">
                      <div class="flex flex-wrap items-center gap-2">
                        <span class="terminal-chip terminal-chip--accent px-2.5 py-1 text-xs" style={getAccentVars(getPostTypeTheme(item.post.type))}>
                          {item.post.type === 'article' ? t('common.article') : t('common.tweet')}
                        </span>
                        <span class="terminal-chip terminal-chip--accent px-2.5 py-1 text-xs" style={getAccentVars(getCategoryTheme(item.post.category))}>
                          <i class="fas fa-folder-tree text-[11px]"></i>
                          {item.post.category}
                        </span>
                      </div>

                      <h4 class="text-base font-semibold text-[var(--title-color)] group-hover:text-[var(--primary)]">
                        {item.post.title}
                      </h4>
                      <p class="text-sm leading-7 text-[var(--text-secondary)]">{item.post.description}</p>
                    </div>

                    <div class="mt-auto flex flex-wrap gap-2 pt-1">
                      <span class="terminal-stat-pill px-2.5 py-1 text-xs">
                        <i class="fas fa-eye text-[var(--primary)]"></i>
                        {t('home.views')}: {item.pageViews}
                      </span>
                      <span class="terminal-stat-pill px-2.5 py-1 text-xs">
                        <i class="fas fa-check-double text-[var(--primary)]"></i>
                        {t('home.completes')}: {item.readCompletes}
                      </span>
                      <span class="terminal-stat-pill px-2.5 py-1 text-xs">
                        <i class="fas fa-chart-line text-[var(--primary)]"></i>
                        {t('home.avgProgress')}: {Math.round(item.avgProgressPercent)}%
                      </span>
                    </div>

                    {item.sharedTags.length > 0 && (
                      <div class="flex flex-wrap gap-2">
                        {item.sharedTags.slice(0, 3).map((tag) => (
                          <span class="terminal-chip terminal-chip--accent px-2.5 py-1 text-xs" style={getAccentVars(getTagTheme(tag))}>
                            <i class="fas fa-hashtag text-[11px]"></i>
                            {tag}
                          </span>
                        ))}
                      </div>
                    )}
                  </a>
                ))}
              </div>
            </div>
          </section>
        )}

        <section class="mt-8">
          <Comments postSlug={post.slug} class="terminal-panel" siteSettings={siteSettings} />
        </section>
      </div>

      <TableOfContents>
        <div slot="before-nav" class="terminal-panel-muted space-y-3">
          <span class="terminal-kicker">
            <i class="fas fa-bolt"></i>
            {articleCopy.floatingToolsTitle}
          </span>

          <div
            class:list={[
              'grid gap-2',
              wechatShareQrEnabled && wechatShareQrSvg ? 'grid-cols-4' : 'grid-cols-3',
            ]}
          >
            <button
              type="button"
              class="flex h-11 w-full items-center justify-center rounded-2xl border border-[var(--border-color)]/70 bg-[var(--bg)]/75 text-[var(--text-secondary)] transition hover:border-[var(--primary)] hover:text-[var(--primary)]"
              data-article-floating-action="digest-copy"
              title={articleCopy.copySummary}
              aria-label={articleCopy.copySummary}
            >
              <i class="fas fa-copy text-sm"></i>
            </button>
            <button
              type="button"
              class="flex h-11 w-full items-center justify-center rounded-2xl border border-[var(--border-color)]/70 bg-[var(--bg)]/75 text-[var(--text-secondary)] transition hover:border-[var(--primary)] hover:text-[var(--primary)]"
              data-article-floating-action="digest-share"
              title={articleCopy.shareSummary}
              aria-label={articleCopy.shareSummary}
            >
              <i class="fas fa-share-nodes text-sm"></i>
            </button>
            {wechatShareQrEnabled && wechatShareQrSvg && (
              <button
                type="button"
                class="flex h-11 w-full items-center justify-center rounded-2xl border border-[var(--border-color)]/70 bg-[var(--bg)]/75 text-[var(--text-secondary)] transition hover:border-[var(--primary)] hover:text-[var(--primary)]"
                data-article-floating-action="wechat-qr"
                title={articleCopy.shareToWeChat}
                aria-label={articleCopy.shareToWeChat}
              >
                <i class="fab fa-weixin text-sm"></i>
              </button>
            )}
            <button
              type="button"
              class="flex h-11 w-full items-center justify-center rounded-2xl border border-[var(--border-color)]/70 bg-[var(--bg)]/75 text-[var(--text-secondary)] transition hover:border-[var(--primary)] hover:text-[var(--primary)]"
              data-article-floating-action="permalink-copy"
              title={t('common.copyPermalink')}
              aria-label={t('common.copyPermalink')}
            >
              <i class="fas fa-link text-sm"></i>
            </button>
          </div>
        </div>
      </TableOfContents>
    </div>
  </div>

  {wechatShareQrEnabled && wechatShareQrSvg && (
    <div
      class="fixed inset-0 z-[160] hidden bg-black/70 backdrop-blur-sm"
      data-article-wechat-qr-modal
      aria-hidden="true"
    >
      <div class="flex min-h-screen items-center justify-center p-4">
        <div class="w-full max-w-4xl rounded-[32px] border border-[var(--border-color)]/70 bg-[var(--terminal-bg)] p-5 shadow-[0_30px_90px_rgba(15,23,42,0.36)] sm:p-7">
          <div class="flex items-start justify-between gap-4">
            <div class="space-y-2">
              <span class="terminal-kicker">
                <i class="fab fa-weixin"></i>
                {articleCopy.shareToWeChat}
              </span>
              <div>
                <h3 class="text-2xl font-semibold text-[var(--title-color)]">{articleCopy.qrModalTitle}</h3>
                <p class="mt-2 max-w-2xl text-sm leading-7 text-[var(--text-secondary)]">
                  {articleCopy.qrModalDescription}
                </p>
              </div>
            </div>

            <button
              type="button"
              class="flex h-11 w-11 items-center justify-center rounded-2xl border border-[var(--border-color)] bg-[var(--terminal-bg)] text-[var(--text-secondary)] transition hover:border-[var(--primary)] hover:text-[var(--primary)]"
              data-article-wechat-qr-close
              aria-label={t('common.close')}
            >
              <i class="fas fa-xmark text-base"></i>
            </button>
          </div>

          <div class="mt-6 grid gap-6 lg:grid-cols-[260px_minmax(0,1fr)]">
            <div class="mx-auto w-full max-w-[260px] rounded-[28px] border border-[var(--border-color)]/80 bg-white p-5 shadow-[0_18px_45px_rgba(15,23,42,0.12)]">
              <div class="overflow-hidden rounded-2xl" set:html={wechatShareQrSvg}></div>
            </div>

            <div class="space-y-4">
              <div class="rounded-2xl border border-[var(--border-color)]/70 bg-[var(--header-bg)] p-5">
                <div class="text-[11px] uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
                  {articleCopy.canonical}
                </div>
                <p class="mt-3 break-all font-mono text-sm leading-7 text-[var(--title-color)]">{canonicalUrl}</p>
              </div>

              <div class="rounded-2xl border border-[var(--border-color)]/70 bg-[var(--header-bg)] p-5">
                <div class="text-[11px] uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
                  {articleCopy.digestTitle}
                </div>
                <p class="mt-3 text-base font-semibold leading-7 text-[var(--title-color)]">{post.title}</p>
                <p class="mt-3 text-sm leading-7 text-[var(--text-secondary)]">{articleSynopsis}</p>
                <p class="mt-3 text-sm leading-7 text-[var(--text-secondary)]">{articleCopy.qrModalHint}</p>
              </div>

              <div class="flex flex-wrap gap-2">
                <button
                  type="button"
                  class="terminal-action-button terminal-action-button-primary"
                  data-article-permalink-copy
                  data-default-label={t('common.copyPermalink')}
                  data-success-label={articleCopy.copyPermalinkSuccess}
                  data-failed-label={articleCopy.copyPermalinkFailed}
                >
                  <i class="fas fa-link"></i>
                  <span>{t('common.copyPermalink')}</span>
                </button>
                <a
                  href={wechatShareQrPngDataUrl}
                  download={`${post.slug}-wechat-share-qr.png`}
                  class="terminal-action-button"
                  data-article-qr-download
                >
                  <i class="fas fa-download"></i>
                  <span>{articleCopy.downloadQr}</span>
                </a>
                <button
                  type="button"
                  class="terminal-action-button"
                  data-article-wechat-qr-close
                >
                  <i class="fas fa-xmark"></i>
                  <span>{t('common.close')}</span>
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  )}

  <div
    class="pointer-events-none fixed bottom-5 right-5 z-[70] w-[min(22rem,calc(100vw-1.5rem))] translate-y-4 opacity-0 transition-all duration-300"
    data-article-digest-toast
    data-title-success={articleCopy.toastSuccessTitle}
    data-title-error={articleCopy.toastErrorTitle}
    data-title-info={articleCopy.toastInfoTitle}
    aria-live="polite"
    aria-atomic="true"
  >
    <div class="rounded-2xl border border-emerald-500/25 bg-[var(--terminal-bg)]/96 p-4 shadow-[0_18px_50px_rgba(15,23,42,0.18)] backdrop-blur">
      <div class="flex items-start gap-3">
        <span
          class="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-emerald-500/12 text-emerald-400"
          data-article-digest-toast-icon
        >
          <i class="fas fa-check"></i>
        </span>
        <div class="min-w-0">
          <p class="text-sm font-semibold text-[var(--title-color)]" data-article-digest-toast-title>
            {articleCopy.toastSuccessTitle}
          </p>
          <p class="mt-1 text-sm leading-6 text-[var(--text-secondary)]" data-article-digest-toast-message></p>
        </div>
      </div>
    </div>
  </div>
</BaseLayout>

<script
  is:inline
  define:vars={{
    analyticsEndpoint,
    postSlug: post.slug,
    articleDigestClipboardText,
    articleDigestShareText,
    articleCanonicalUrl: canonicalUrl,
    articleTitle: post.title,
    articleCopyQrOpened: articleCopy.qrOpened,
    articleCopyDownloadQrStarted: articleCopy.downloadQrStarted,
  }}
>
  (() => {
    const endpoint = analyticsEndpoint;
    const sessionStorageKey = `termi:content-session:${postSlug}`;
    const startedAt = Date.now();
    let sentPageView = false;
    let lastReportedProgress = 0;
    const digestCopyButton = document.querySelector('[data-article-digest-copy]');
    const digestShareButton = document.querySelector('[data-article-digest-share]');
    const permalinkCopyButtons = document.querySelectorAll('[data-article-permalink-copy]');
    const floatingActionButtons = document.querySelectorAll('[data-article-floating-action]');
    const wechatQrModal = document.querySelector('[data-article-wechat-qr-modal]');
    const wechatQrOpenButtons = document.querySelectorAll('[data-article-wechat-qr-open]');
    const wechatQrCloseButtons = document.querySelectorAll('[data-article-wechat-qr-close]');
    const wechatQrDownloadButtons = document.querySelectorAll('[data-article-qr-download]');
    const digestStatus = document.querySelector('[data-article-digest-status]');
    const digestToast = document.querySelector('[data-article-digest-toast]');
    const digestToastIcon = document.querySelector('[data-article-digest-toast-icon]');
    const digestToastTitle = document.querySelector('[data-article-digest-toast-title]');
    const digestToastMessage = document.querySelector('[data-article-digest-toast-message]');
    let digestToastTimer = 0;

    function ensureSessionId() {
      try {
        const existing = window.sessionStorage.getItem(sessionStorageKey);
        if (existing) return existing;
        const nextId = crypto.randomUUID();
        window.sessionStorage.setItem(sessionStorageKey, nextId);
        return nextId;
      } catch {
        return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
      }
    }

    function getProgressPercent() {
      const doc = document.documentElement;
      const scrollTop = window.scrollY || doc.scrollTop || 0;
      const scrollHeight = Math.max(doc.scrollHeight - window.innerHeight, 1);
      return Math.max(0, Math.min(100, Math.round((scrollTop / scrollHeight) * 100)));
    }

    function getReferrerHost() {
      try {
        return document.referrer ? new URL(document.referrer).host : '';
      } catch {
        return '';
      }
    }

    function normalizeSource(value) {
      const source = String(value || '').trim().toLowerCase();
      if (!source) return 'direct';
      if (source.includes('chatgpt') || source.includes('openai')) return 'chatgpt-search';
      if (source.includes('perplexity')) return 'perplexity';
      if (source.includes('copilot') || source.includes('bing')) return 'copilot-bing';
      if (source.includes('gemini')) return 'gemini';
      if (source.includes('google')) return 'google';
      if (source.includes('claude')) return 'claude';
      if (source.includes('duckduckgo')) return 'duckduckgo';
      if (source.includes('kagi')) return 'kagi';
      return source;
    }

    function buildTrackingMetadata() {
      const currentUrl = new URL(window.location.href);
      const utmSource = currentUrl.searchParams.get('utm_source')?.trim() || '';
      const utmMedium = currentUrl.searchParams.get('utm_medium')?.trim() || '';
      const utmCampaign = currentUrl.searchParams.get('utm_campaign')?.trim() || '';
      const utmTerm = currentUrl.searchParams.get('utm_term')?.trim() || '';
      const utmContent = currentUrl.searchParams.get('utm_content')?.trim() || '';
      const referrerHost = getReferrerHost();

      return {
        pageType: 'article',
        referrerHost: referrerHost || undefined,
        utmSource: utmSource || undefined,
        utmMedium: utmMedium || undefined,
        utmCampaign: utmCampaign || undefined,
        utmTerm: utmTerm || undefined,
        utmContent: utmContent || undefined,
        landingSource: normalizeSource(utmSource || referrerHost),
      };
    }

    function setDigestStatus(message) {
      if (!digestStatus) return;
      digestStatus.textContent = message || '';
    }

    function showDigestToast(message, type = 'success') {
      if (!digestToast || !digestToastIcon || !digestToastTitle || !digestToastMessage) return;

      const title =
        digestToast.getAttribute(`data-title-${type}`) ||
        digestToast.getAttribute('data-title-success') ||
        '';

      digestToastTitle.textContent = title;
      digestToastMessage.textContent = message || '';
      digestToast.classList.remove('opacity-0', 'translate-y-4');

      digestToastIcon.className = 'flex h-9 w-9 shrink-0 items-center justify-center rounded-xl';
      const iconElement = digestToastIcon.querySelector('i');
      if (iconElement) {
        iconElement.className =
          type === 'error'
            ? 'fas fa-triangle-exclamation'
            : type === 'info'
              ? 'fas fa-share-nodes'
              : 'fas fa-check';
      }

      const toastCard = digestToast.firstElementChild;
      toastCard?.classList.remove('border-emerald-500/25', 'border-rose-500/25', 'border-sky-500/25');
      digestToastIcon.classList.remove(
        'bg-emerald-500/12',
        'text-emerald-400',
        'bg-rose-500/12',
        'text-rose-400',
        'bg-sky-500/12',
        'text-sky-400',
      );

      if (type === 'error') {
        toastCard?.classList.add('border-rose-500/25');
        digestToastIcon.classList.add('bg-rose-500/12', 'text-rose-400');
      } else if (type === 'info') {
        toastCard?.classList.add('border-sky-500/25');
        digestToastIcon.classList.add('bg-sky-500/12', 'text-sky-400');
      } else {
        toastCard?.classList.add('border-emerald-500/25');
        digestToastIcon.classList.add('bg-emerald-500/12', 'text-emerald-400');
      }

      window.clearTimeout(digestToastTimer);
      digestToastTimer = window.setTimeout(() => {
        digestToast.classList.add('opacity-0', 'translate-y-4');
      }, 2200);
    }

    function setDigestButtonState(button, iconClass, label) {
      if (!button) return;
      button.innerHTML = `<i class="${iconClass}"></i><span>${label}</span>`;
    }

    function resetDigestButton(button, fallbackIconClass) {
      if (!button) return;
      const defaultLabel = button.getAttribute('data-default-label') || '';
      setDigestButtonState(button, fallbackIconClass, defaultLabel);
    }

    async function writeClipboardText(value) {
      await navigator.clipboard.writeText(value);
    }

    async function handleDigestCopy(button = digestCopyButton) {
      const successLabel = button?.getAttribute('data-success-label') || '';
      const failedLabel = button?.getAttribute('data-failed-label') || '';
      try {
        await writeClipboardText(articleDigestClipboardText);
        setDigestButtonState(button, 'fas fa-check', successLabel);
        setDigestStatus(successLabel);
        showDigestToast(successLabel, 'success');
      } catch {
        setDigestButtonState(button, 'fas fa-triangle-exclamation', failedLabel);
        setDigestStatus(failedLabel);
        showDigestToast(failedLabel, 'error');
      } finally {
        window.setTimeout(() => {
          resetDigestButton(button, 'fas fa-copy');
        }, 1800);
      }
    }

    async function handleDigestShare(button = digestShareButton) {
      const successLabel = button?.getAttribute('data-success-label') || '';
      const fallbackLabel = button?.getAttribute('data-fallback-label') || '';
      const failedLabel = button?.getAttribute('data-failed-label') || '';
      try {
        if (navigator.share) {
          await navigator.share({
            title: articleTitle,
            text: articleDigestShareText,
            url: articleCanonicalUrl,
          });
          setDigestButtonState(button, 'fas fa-check', successLabel);
          setDigestStatus(successLabel);
          showDigestToast(successLabel, 'success');
        } else {
          await writeClipboardText(articleDigestShareText);
          setDigestButtonState(button, 'fas fa-copy', fallbackLabel);
          setDigestStatus(fallbackLabel);
          showDigestToast(fallbackLabel, 'info');
        }
      } catch (error) {
        if (error instanceof DOMException && error.name === 'AbortError') {
          resetDigestButton(button, 'fas fa-share-nodes');
          return;
        }

        setDigestButtonState(button, 'fas fa-triangle-exclamation', failedLabel);
        setDigestStatus(failedLabel);
        showDigestToast(failedLabel, 'error');
      } finally {
        window.setTimeout(() => {
          resetDigestButton(button, 'fas fa-share-nodes');
        }, 1800);
      }
    }

    async function handlePermalinkCopy(button = permalinkCopyButtons[0]) {
      const successLabel = button?.getAttribute('data-success-label') || '';
      const failedLabel = button?.getAttribute('data-failed-label') || '';

      try {
        await writeClipboardText(window.location.href);
        setDigestButtonState(button, 'fas fa-check', successLabel);
        setDigestStatus(successLabel);
        showDigestToast(successLabel, 'success');
      } catch {
        setDigestButtonState(button, 'fas fa-triangle-exclamation', failedLabel);
        setDigestStatus(failedLabel);
        showDigestToast(failedLabel, 'error');
      } finally {
        window.setTimeout(() => {
          resetDigestButton(button, 'fas fa-link');
        }, 1800);
      }
    }

    function openWechatQrModal() {
      if (!wechatQrModal) return;
      wechatQrModal.classList.remove('hidden');
      wechatQrModal.setAttribute('aria-hidden', 'false');
      document.body.style.overflow = 'hidden';
      setDigestStatus(articleCopyQrOpened);
      showDigestToast(articleCopyQrOpened, 'info');
    }

    function closeWechatQrModal() {
      if (!wechatQrModal) return;
      wechatQrModal.classList.add('hidden');
      wechatQrModal.setAttribute('aria-hidden', 'true');
      document.body.style.overflow = '';
    }

    digestCopyButton?.addEventListener('click', async () => {
      await handleDigestCopy();
    });

    digestShareButton?.addEventListener('click', async () => {
      await handleDigestShare();
    });

    permalinkCopyButtons.forEach((button) => {
      button.addEventListener('click', async () => {
        await handlePermalinkCopy(button);
      });
    });

    document.querySelectorAll('[data-article-share-link]').forEach((link) => {
      link.addEventListener('click', () => {
        const label = link.textContent?.trim() || '';
        if (!label) return;
        setDigestStatus(label);
        showDigestToast(label, 'info');
      });
    });

    wechatQrOpenButtons.forEach((button) => {
      button.addEventListener('click', () => {
        openWechatQrModal();
      });
    });

    wechatQrCloseButtons.forEach((button) => {
      button.addEventListener('click', () => {
        closeWechatQrModal();
      });
    });

    wechatQrDownloadButtons.forEach((button) => {
      button.addEventListener('click', () => {
        setDigestStatus(articleCopyDownloadQrStarted);
        showDigestToast(articleCopyDownloadQrStarted, 'info');
      });
    });

    wechatQrModal?.addEventListener('click', (event) => {
      if (event.target === wechatQrModal) {
        closeWechatQrModal();
      }
    });

    document.addEventListener('keydown', (event) => {
      if (event.key === 'Escape' && wechatQrModal && !wechatQrModal.classList.contains('hidden')) {
        closeWechatQrModal();
      }
    });

    floatingActionButtons.forEach((button) => {
      button.addEventListener('click', async () => {
        const action = button.getAttribute('data-article-floating-action');
        button.classList.add('border-[var(--primary)]', 'text-[var(--primary)]');
        window.setTimeout(() => {
          button.classList.remove('border-[var(--primary)]', 'text-[var(--primary)]');
        }, 1400);

        if (action === 'digest-copy') {
          await handleDigestCopy();
          return;
        }

        if (action === 'digest-share') {
          await handleDigestShare();
          return;
        }

        if (action === 'wechat-qr') {
          openWechatQrModal();
          return;
        }

        if (action === 'permalink-copy') {
          await handlePermalinkCopy(permalinkCopyButtons[0]);
        }
      });
    });

    function sendEvent(eventType, extras = {}, useBeacon = false) {
      const payload = JSON.stringify({
        event_type: eventType,
        path: `${window.location.pathname}${window.location.search}`,
        post_slug: postSlug,
        session_id: ensureSessionId(),
        referrer: document.referrer || undefined,
        metadata: buildTrackingMetadata(),
        ...extras,
      });

      if (useBeacon && navigator.sendBeacon) {
        navigator.sendBeacon(endpoint, new Blob([payload], { type: 'application/json' }));
        return;
      }

      fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: payload,
        keepalive: true,
      }).catch(() => undefined);
    }

    function reportProgress(forceComplete = false) {
      const progress = forceComplete ? 100 : getProgressPercent();
      const durationMs = Date.now() - startedAt;
      const eventType = forceComplete || progress >= 95 ? 'read_complete' : 'read_progress';

      if (!forceComplete && progress <= lastReportedProgress + 9) {
        return;
      }

      lastReportedProgress = Math.max(lastReportedProgress, progress);
      sendEvent(
        eventType,
        {
          progress_percent: progress,
          duration_ms: durationMs,
          metadata: {
            ...buildTrackingMetadata(),
            viewportHeight: window.innerHeight,
          },
        },
        eventType === 'read_complete',
      );
    }

    if (!sentPageView) {
      sentPageView = true;
      sendEvent('page_view', {
        metadata: {
          ...buildTrackingMetadata(),
          title: document.title,
        },
      });
    }

    window.addEventListener('scroll', () => {
      reportProgress(false);
    }, { passive: true });

    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'hidden') {
        reportProgress(getProgressPercent() >= 95);
      }
    });

    window.addEventListener('pagehide', () => {
      reportProgress(getProgressPercent() >= 95);
    });
  })();
</script>
