---
import BaseLayout from '../../layouts/BaseLayout.astro';
import DiscoveryBrief from '../../components/seo/DiscoveryBrief.astro';
import PageViewTracker from '../../components/seo/PageViewTracker.astro';
import SharePanel from '../../components/seo/SharePanel.astro';
import CommandPrompt from '../../components/ui/CommandPrompt.astro';
import TerminalWindow from '../../components/ui/TerminalWindow.astro';
import { api, DEFAULT_SITE_SETTINGS, resolvePublicApiBaseUrl } from '../../lib/api/client';
import { getI18n } from '../../lib/i18n';
import { buildDiscoveryHighlights, buildFaqJsonLd, buildPageFaqs, compactJsonLd } from '../../lib/seo';

export const prerender = false;

let siteSettings = DEFAULT_SITE_SETTINGS;
const { locale, t } = getI18n(Astro);
const isEnglish = locale.startsWith('en');
const publicApiBaseUrl = resolvePublicApiBaseUrl(Astro.url);

try {
  siteSettings = await api.getSiteSettings();
} catch (error) {
  console.error('Failed to load site settings:', error);
}

const aiEnabled = siteSettings.ai.enabled;
const sampleQuestions = [
  locale === 'en'
    ? 'What kind of topics does this blog mainly cover?'
    : '这个博客主要写什么内容？',
  locale === 'en'
    ? 'What recent posts are related to Astro or frontend topics?'
    : '最近有哪些和 Astro 或前端相关的文章？',
  locale === 'en'
    ? 'What is the site owner\'s tech stack and personal profile?'
    : '站长的技术栈和个人介绍是什么？'
];
const siteBaseUrl = (siteSettings.siteUrl || new URL(Astro.request.url).origin).replace(/\/$/, '');
const askCanonicalUrl = new URL('/ask', siteBaseUrl).toString();
const askJsonLd = [
  {
    '@context': 'https://schema.org',
    '@type': 'WebPage',
    name: t('ask.title'),
    description: t('ask.pageDescription', { siteName: siteSettings.siteName }),
    url: askCanonicalUrl,
    inLanguage: locale,
  },
  {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: [
      {
        '@type': 'ListItem',
        position: 1,
        name: siteSettings.siteName,
        item: siteBaseUrl,
      },
      {
        '@type': 'ListItem',
        position: 2,
        name: t('ask.title'),
        item: askCanonicalUrl,
      },
    ],
  },
];
const sharePanelCopy = isEnglish
  ? {
      badge: 'ai search',
      title: 'Share the AI ask page',
      description:
        'Share the site’s AI query interface as a canonical entry for question-driven discovery, backed by stable internal sources and citations.',
      examples: 'Prompts',
      status: 'Status',
      statusValue: aiEnabled ? 'Ready' : 'Idle',
    }
    : {
      badge: '问答入口',
      title: '把问答入口甩出去',
      description: '有人想少走弯路时，把这页递过去就行。',
      examples: '示例问题',
      status: '状态',
      statusValue: aiEnabled ? '随时开问' : '暂时休息',
    };
const askHighlights = buildDiscoveryHighlights([
  t('ask.subtitle'),
  aiEnabled ? t('common.featureOn') : t('common.featureOff'),
  ...sampleQuestions,
]);
const askFaqs = buildPageFaqs({
  locale,
  pageTitle: t('ask.pageTitle'),
  summary: t('ask.pageDescription', { siteName: siteSettings.siteName }),
  primaryLabel: t('ask.title'),
  primaryUrl: askCanonicalUrl,
  relatedLinks: [
    { label: t('nav.about'), url: `${siteBaseUrl}/about` },
    { label: t('nav.articles'), url: `${siteBaseUrl}/articles` },
    { label: t('nav.categories'), url: `${siteBaseUrl}/categories` },
  ],
  signals: askHighlights,
});
const askFaqJsonLd = buildFaqJsonLd(askFaqs);
---

<BaseLayout
  title={`${t('ask.pageTitle')} | ${siteSettings.siteShortName}`}
  description={t('ask.pageDescription', { siteName: siteSettings.siteName })}
  siteSettings={siteSettings}
  jsonLd={compactJsonLd([...askJsonLd, askFaqJsonLd])}
>
  <PageViewTracker pageType="ask" entityId="ask" />
  <section class="mx-auto max-w-[1660px] px-4 py-8 sm:px-6 lg:px-8">
    <TerminalWindow title="~/ask" class="w-full">
      <div class="px-4 pb-2">
        <div class="terminal-panel ml-4 mt-4 space-y-6">
          <div class="flex flex-wrap items-start justify-between gap-4">
            <div class="space-y-3">
              <span class="terminal-kicker">
                <i class="fas fa-sparkles"></i>
                {t('ask.terminalLabel')}
              </span>
              <div class="space-y-2">
                <h1 class="text-2xl font-bold text-[var(--title-color)] sm:text-3xl">{t('ask.title')}</h1>
                <p class="max-w-3xl text-sm leading-7 text-[var(--text-secondary)] sm:text-base">
                  {t('ask.subtitle')}
                </p>
              </div>
            </div>

            <span class:list={[
              'terminal-stat-pill px-3 py-1.5 text-xs font-mono',
              aiEnabled
                ? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-300'
                : 'border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300'
            ]}>
              <i class:list={[
                'fas',
                aiEnabled ? 'fa-wave-square' : 'fa-triangle-exclamation'
              ]}></i>
              {aiEnabled ? '已待命' : '休息中'}
            </span>
          </div>

          <SharePanel
            shareTitle={`${t('ask.pageTitle')} | ${siteSettings.siteShortName || siteSettings.siteName}`}
            summary={t('ask.pageDescription', { siteName: siteSettings.siteName })}
            canonicalUrl={askCanonicalUrl}
            badge={sharePanelCopy.badge}
            kicker="geo / ai"
            title={sharePanelCopy.title}
            description={sharePanelCopy.description}
            stats={[
              { label: sharePanelCopy.examples, value: String(sampleQuestions.length) },
              { label: sharePanelCopy.status, value: sharePanelCopy.statusValue },
            ]}
            wechatShareQrEnabled={siteSettings.seo.wechatShareQrEnabled}
          />

          <DiscoveryBrief
            badge={isEnglish ? 'ask brief' : '问答摘要'}
            kicker="geo / ai"
            title={isEnglish ? 'AI-readable ask-page brief' : '给 AI 看的问答页摘要'}
            summary={t('ask.pageDescription', { siteName: siteSettings.siteName })}
            highlights={askHighlights}
            faqs={askFaqs}
          />

          <div class="grid gap-6 xl:grid-cols-[minmax(0,1.45fr)_18rem]">
            <div class="min-w-0 space-y-5">
              {aiEnabled ? (
                <>
                  <form id="ai-form" class="terminal-panel-muted space-y-4">
                    <CommandPrompt promptId="ask-session-prompt" command={t('ask.promptIdle')} path="~/ask" />
                    <textarea
                      id="ai-question"
                      class="min-h-[160px] w-full resize-y rounded-2xl border border-[var(--border-color)] bg-[var(--terminal-bg)] px-4 py-3 font-mono text-sm text-[var(--text)] outline-none transition focus:border-[var(--primary)]"
                      placeholder={t('ask.textareaPlaceholder')}
                    ></textarea>
                    <div class="flex flex-wrap items-center gap-3">
                      <button type="submit" id="ai-submit" class="terminal-action-button terminal-action-button-primary">
                        <i class="fas fa-terminal text-xs"></i>
                        <span>{t('ask.submit')}</span>
                      </button>
                      <span id="ai-status" class="text-sm text-[var(--text-secondary)]">{t('ask.idleStatus')}</span>
                    </div>
                  </form>

                  <div id="ai-result" class="terminal-panel-muted hidden">
                    <div class="flex items-center justify-between gap-3">
                      <div class="text-xs uppercase tracking-[0.24em] text-[var(--text-tertiary)]">{t('ask.assistantLabel')}</div>
                      <div id="ai-meta" class="text-xs text-[var(--text-tertiary)]"></div>
                    </div>
                    <div id="ai-answer" class="terminal-document mt-4"></div>
                    <div id="ai-sources" class="mt-5 grid gap-3"></div>
                  </div>
                </>
              ) : (
                <div class="terminal-panel-muted border-dashed px-5 py-8">
                  <div class="text-xs uppercase tracking-[0.24em] text-[var(--text-tertiary)]">{t('ask.disabledStateLabel')}</div>
                  <h2 class="mt-3 text-xl font-semibold text-[var(--title-color)]">{t('ask.disabledTitle')}</h2>
                  <p class="mt-3 max-w-2xl text-sm leading-7 text-[var(--text-secondary)]">
                    {t('ask.disabledDescription')}
                  </p>
                </div>
              )}
            </div>

            <aside class="space-y-4">
              <div class="terminal-panel-muted">
                <div class="text-xs uppercase tracking-[0.22em] text-[var(--text-tertiary)]">{t('ask.examples')}</div>
                <div class="mt-4 space-y-2">
                  {sampleQuestions.map((question) => (
                    <button
                      type="button"
                      class="sample-question terminal-option-card"
                      data-question={question}
                    >
                      {question}
                    </button>
                  ))}
                </div>
              </div>

              <div class="terminal-panel-muted">
                <div class="text-xs uppercase tracking-[0.22em] text-[var(--text-tertiary)]">{t('ask.guide')}</div>
                <ol class="mt-4 space-y-2 text-sm leading-7 text-[var(--text-secondary)]">
                  <li>{t('ask.guide1')}</li>
                  <li>{t('ask.guide2')}</li>
                  <li>{t('ask.guide3')}</li>
                </ol>
              </div>
            </aside>
          </div>
        </div>
      </div>
    </TerminalWindow>
  </section>
</BaseLayout>

<style is:global>
  .ask-connecting-shell {
    display: inline-flex;
    align-items: center;
    gap: 0.95rem;
    min-width: min(100%, 20rem);
    border-radius: 1.1rem;
    border: 1px solid color-mix(in oklab, var(--primary) 12%, var(--border-color));
    background:
      radial-gradient(circle at top right, rgba(var(--primary-rgb), 0.11), transparent 28%),
      radial-gradient(circle at bottom left, rgba(var(--primary-rgb), 0.05), transparent 34%),
      linear-gradient(
        180deg,
        color-mix(in oklab, var(--terminal-bg) 98%, transparent),
        color-mix(in oklab, var(--header-bg) 92%, transparent)
      );
    padding: 0.95rem 1.05rem;
    box-shadow:
      0 14px 28px rgba(15, 23, 42, 0.08),
      inset 0 1px 0 rgba(255, 255, 255, 0.05),
      inset 0 0 0 1px rgba(var(--primary-rgb), 0.03);
  }

  .ask-gemini-avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    flex: 0 0 2.2rem;
    border-radius: 999px;
    background:
      radial-gradient(circle at 30% 30%, rgba(160, 211, 255, 0.24), transparent 55%),
      radial-gradient(circle at 70% 70%, rgba(var(--primary-rgb), 0.2), transparent 48%),
      color-mix(in oklab, var(--terminal-bg) 88%, rgba(var(--primary-rgb), 0.16));
    animation: ask-gemini-avatar-breathe 3.2s ease-in-out infinite;
  }

  .ask-gemini-avatar::before,
  .ask-gemini-avatar::after {
    content: '';
    position: absolute;
    inset: -0.3rem;
    border-radius: 999px;
    pointer-events: none;
  }

  .ask-gemini-avatar::before {
    background: radial-gradient(circle, rgba(var(--primary-rgb), 0.24), transparent 72%);
    filter: blur(9px);
    animation: ask-gemini-halo 3.2s ease-in-out infinite;
  }

  .ask-gemini-avatar::after {
    inset: 0.2rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    opacity: 0.8;
  }

  .ask-gemini-orbit {
    position: absolute;
    inset: -0.52rem;
    border-radius: 999px;
    animation: ask-gemini-orbit-spin 2.15s linear infinite;
    pointer-events: none;
  }

  .ask-gemini-orbit-svg {
    width: 100%;
    height: 100%;
    overflow: visible;
    transform: rotate(-90deg);
    filter:
      drop-shadow(0 0 8px rgba(var(--primary-rgb), 0.22))
      drop-shadow(0 0 16px rgba(79, 160, 255, 0.16));
  }

  .ask-gemini-orbit-ring {
    fill: none;
    stroke: url(#ask-gemini-orbit-gradient);
    stroke-width: 2.3;
    stroke-linecap: butt;
    stroke-dasharray: 34 110;
    stroke-dashoffset: 0;
    opacity: 1;
    animation:
      ask-gemini-orbit-length 2.1s cubic-bezier(0.6, 0.08, 0.28, 0.96) infinite,
      ask-gemini-orbit-glow 3.6s ease-in-out infinite;
  }

  .ask-gemini-svg {
    position: relative;
    z-index: 1;
    width: 2rem;
    height: 2rem;
    overflow: visible;
  }

  .ask-gemini-star-outline {
    opacity: 0.25;
  }

  .ask-gemini-sweep {
    transform-box: fill-box;
    transform-origin: center;
    animation: ask-gemini-sweep 2.9s cubic-bezier(0.55, 0.08, 0.28, 0.98) infinite;
  }

  .ask-gemini-sweep-secondary {
    animation-delay: 1.15s;
    opacity: 0.68;
  }

  .ask-connecting-copy {
    min-width: 0;
    color: var(--text);
    font-size: 0.94rem;
    line-height: 1.5;
    letter-spacing: 0.01em;
  }

  .ask-connecting-copy span {
    display: block;
    color: color-mix(in oklab, var(--title-color) 72%, var(--text-secondary));
    text-wrap: balance;
  }

  @keyframes ask-gemini-avatar-breathe {
    0%,
    100% {
      transform: translateY(0) scale(0.98);
    }

    50% {
      transform: translateY(-0.02rem) scale(1.04);
    }
  }

  @keyframes ask-gemini-halo {
    0%,
    100% {
      opacity: 0.45;
      transform: scale(0.9);
    }

    50% {
      opacity: 0.9;
      transform: scale(1.08);
    }
  }

  @keyframes ask-gemini-orbit-spin {
    from {
      transform: rotate(0deg);
    }

    to {
      transform: rotate(360deg);
    }
  }

  @keyframes ask-gemini-orbit-glow {
    0%,
    100% {
      opacity: 0.7;
      filter: saturate(0.96);
    }

    50% {
      opacity: 1;
      filter: saturate(1.12);
    }
  }

  @keyframes ask-gemini-orbit-length {
    0% {
      stroke-dasharray: 30 102;
      stroke-dashoffset: 4;
      opacity: 0.78;
    }

    38% {
      stroke-dasharray: 64 68;
      stroke-dashoffset: -14;
      opacity: 0.92;
    }

    68% {
      stroke-dasharray: 96 36;
      stroke-dashoffset: -30;
      opacity: 0.98;
    }

    88% {
      stroke-dasharray: 118 14;
      stroke-dashoffset: -48;
      opacity: 1;
    }

    96% {
      stroke-dasharray: 124 8;
      stroke-dashoffset: -56;
      opacity: 1;
    }

    100% {
      stroke-dasharray: 30 102;
      stroke-dashoffset: -64;
      opacity: 0.78;
    }
  }

  @keyframes ask-gemini-sweep {
    0% {
      opacity: 0;
      transform: translate3d(-0.6rem, 0, 0) rotate(-34deg) scaleX(0.86);
    }

    18% {
      opacity: 0.95;
    }

    56% {
      opacity: 0.74;
    }

    100% {
      opacity: 0;
      transform: translate3d(0.7rem, 0, 0) rotate(-34deg) scaleX(1.08);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .ask-gemini-avatar,
    .ask-gemini-avatar::before,
    .ask-gemini-orbit,
    .ask-gemini-sweep,
    .ask-gemini-sweep-secondary {
      animation: none;
    }
  }
</style>

{aiEnabled && (
  <script is:inline define:vars={{ apiBase: publicApiBaseUrl }}>
    const t = window.__termiTranslate;
    const form = document.getElementById('ai-form');
    const input = document.getElementById('ai-question');
    const submit = document.getElementById('ai-submit');
    const status = document.getElementById('ai-status');
    const result = document.getElementById('ai-result');
    const answer = document.getElementById('ai-answer');
    const sources = document.getElementById('ai-sources');
    const meta = document.getElementById('ai-meta');
    const sampleButtons = Array.from(document.querySelectorAll('.sample-question'));
    const answerCache = new Map();
    const prefilledQuestion = new URLSearchParams(window.location.search).get('q')?.trim() || '';
    const promptApi = window.__termiCommandPrompt;

    function updatePrompt(text, typing = true) {
      promptApi?.set?.('ask-session-prompt', text, { typing });
    }

    function escapeHtml(value) {
      return String(value || '')
        .replaceAll('&', '&amp;')
        .replaceAll('<', '&lt;')
        .replaceAll('>', '&gt;')
        .replaceAll('"', '&quot;')
        .replaceAll("'", '&#39;');
    }

    function renderInlineMarkdown(value) {
      let rendered = escapeHtml(value || '');

      rendered = rendered.replace(
        /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,
        '<a href="$2" target="_blank" rel="noreferrer noopener">$1</a>'
      );
      rendered = rendered.replace(/`([^`]+)`/g, '<code>$1</code>');
      rendered = rendered.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
      rendered = rendered.replace(/(^|[\s(])\*([^*]+)\*(?=[\s).,!?;:]|$)/g, '$1<em>$2</em>');

      return rendered;
    }

    function renderMarkdown(value) {
      const normalized = String(value || '').replace(/\r\n/g, '\n').trim();
      if (!normalized) {
        return `<p>${escapeHtml(t('ask.emptyAnswer'))}</p>`;
      }

      const codeBlocks = [];
      const withCodePlaceholders = normalized.replace(/```([\w-]*)\n([\s\S]*?)```/g, (_, language, code) => {
        const token = `@@CODEBLOCK_${codeBlocks.length}@@`;
        codeBlocks.push(
          `<pre><code class="language-${escapeHtml(language || 'text')}">${escapeHtml(code.trim())}</code></pre>`
        );
        return token;
      });

      const blocks = withCodePlaceholders
        .split(/\n{2,}/)
        .map((block) => block.trim())
        .filter(Boolean);

      const html = blocks.map((block) => {
        const codeMatch = block.match(/^@@CODEBLOCK_(\d+)@@$/);
        if (codeMatch) {
          return codeBlocks[Number(codeMatch[1])] || '';
        }

        const headingMatch = block.match(/^(#{1,4})\s+(.+)$/);
        if (headingMatch) {
          const level = Math.min(headingMatch[1].length, 4);
          return `<h${level}>${renderInlineMarkdown(headingMatch[2])}</h${level}>`;
        }

        const lines = block.split('\n').map((line) => line.trim()).filter(Boolean);
        if (lines.length && lines.every((line) => /^[-*]\s+/.test(line))) {
          return `<ul>${lines.map((line) => `<li>${renderInlineMarkdown(line.replace(/^[-*]\s+/, ''))}</li>`).join('')}</ul>`;
        }

        if (lines.length && lines.every((line) => /^\d+\.\s+/.test(line))) {
          return `<ol>${lines.map((line) => `<li>${renderInlineMarkdown(line.replace(/^\d+\.\s+/, ''))}</li>`).join('')}</ol>`;
        }

        if (lines.length && lines.every((line) => /^>\s?/.test(line))) {
          return `<blockquote>${lines.map((line) => renderInlineMarkdown(line.replace(/^>\s?/, ''))).join('<br />')}</blockquote>`;
        }

        return `<p>${lines.map((line) => renderInlineMarkdown(line)).join('<br />')}</p>`;
      });

      return html.join('');
    }

    function renderConnectingState(message) {
      return `
        <div class="ask-connecting-shell" role="status" aria-live="polite">
          <span class="ask-gemini-avatar" aria-hidden="true">
            <span class="ask-gemini-orbit">
              <svg class="ask-gemini-orbit-svg" viewBox="0 0 48 48" focusable="false">
                <defs>
                  <linearGradient id="ask-gemini-orbit-gradient" x1="5" y1="43" x2="43" y2="5" gradientUnits="userSpaceOnUse">
                    <stop offset="0%" stop-color="#2563eb"></stop>
                    <stop offset="48%" stop-color="#22d3ee"></stop>
                    <stop offset="78%" stop-color="#fde68a"></stop>
                    <stop offset="100%" stop-color="#ffffff"></stop>
                  </linearGradient>
                </defs>
                <circle class="ask-gemini-orbit-ring" cx="24" cy="24" r="21"></circle>
              </svg>
            </span>
            <svg class="ask-gemini-svg" viewBox="0 0 32 32" width="32" height="32" focusable="false">
              <defs>
                <linearGradient id="ask-gemini-base" x1="5" y1="26" x2="27" y2="6" gradientUnits="userSpaceOnUse">
                  <stop offset="0%" stop-color="#346bf1"></stop>
                  <stop offset="22%" stop-color="#3279f8"></stop>
                  <stop offset="45%" stop-color="#3186ff"></stop>
                  <stop offset="72%" stop-color="#4093ff"></stop>
                  <stop offset="100%" stop-color="#4fa0ff"></stop>
                </linearGradient>
                <linearGradient id="ask-gemini-aurora" x1="7" y1="23" x2="25" y2="9" gradientUnits="userSpaceOnUse">
                  <stop offset="0%" stop-color="#ffffff" stop-opacity="0"></stop>
                  <stop offset="42%" stop-color="#ffffff" stop-opacity="0.96"></stop>
                  <stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
                </linearGradient>
                <radialGradient id="ask-gemini-core" cx="50%" cy="50%" r="50%">
                  <stop offset="0%" stop-color="#ffffff" stop-opacity="0.9"></stop>
                  <stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
                </radialGradient>
                <clipPath id="ask-gemini-star-clip">
                  <path d="M16 1.7C15.25 7.05 13.74 11.02 11.93 12.83C10.12 14.64 6.15 16.15 0.8 16.9C6.15 17.65 10.12 19.16 11.93 20.97C13.74 22.78 15.25 26.75 16 32.1C16.75 26.75 18.26 22.78 20.07 20.97C21.88 19.16 25.85 17.65 31.2 16.9C25.85 16.15 21.88 14.64 20.07 12.83C18.26 11.02 16.75 7.05 16 1.7Z"></path>
                </clipPath>
              </defs>
              <circle cx="16" cy="16" r="11" fill="url(#ask-gemini-core)" opacity="0.22"></circle>
              <path
                d="M16 1.7C15.25 7.05 13.74 11.02 11.93 12.83C10.12 14.64 6.15 16.15 0.8 16.9C6.15 17.65 10.12 19.16 11.93 20.97C13.74 22.78 15.25 26.75 16 32.1C16.75 26.75 18.26 22.78 20.07 20.97C21.88 19.16 25.85 17.65 31.2 16.9C25.85 16.15 21.88 14.64 20.07 12.83C18.26 11.02 16.75 7.05 16 1.7Z"
                fill="url(#ask-gemini-base)"
              ></path>
              <g clip-path="url(#ask-gemini-star-clip)">
                <rect class="ask-gemini-sweep" x="2" y="13.7" width="28" height="4.2" rx="2.1" fill="url(#ask-gemini-aurora)"></rect>
                <rect class="ask-gemini-sweep ask-gemini-sweep-secondary" x="1" y="14.7" width="30" height="2.7" rx="1.35" fill="url(#ask-gemini-aurora)"></rect>
              </g>
              <path
                class="ask-gemini-star-outline"
                d="M16 1.7C15.25 7.05 13.74 11.02 11.93 12.83C10.12 14.64 6.15 16.15 0.8 16.9C6.15 17.65 10.12 19.16 11.93 20.97C13.74 22.78 15.25 26.75 16 32.1C16.75 26.75 18.26 22.78 20.07 20.97C21.88 19.16 25.85 17.65 31.2 16.9C25.85 16.15 21.88 14.64 20.07 12.83C18.26 11.02 16.75 7.05 16 1.7Z"
                fill="none"
                stroke="#ffffff"
                stroke-opacity="0.55"
                stroke-width="0.5"
              ></path>
            </svg>
          </span>
          <span class="ask-connecting-copy">
            <span>${escapeHtml(message || t('ask.connectingShort'))}</span>
          </span>
        </div>
      `;
    }

    function setInteractiveState(isLoading) {
      if (submit) {
        submit.toggleAttribute('disabled', isLoading);
      }

      sampleButtons.forEach((button) => {
        button.toggleAttribute('disabled', isLoading);
        button.classList.toggle('opacity-60', isLoading);
        button.classList.toggle('cursor-not-allowed', isLoading);
      });
    }

    function renderSources(items) {
      if (!Array.isArray(items) || !items.length) {
        sources.innerHTML = '';
        return;
      }

      sources.innerHTML = `
        <div class="text-xs uppercase tracking-[0.22em] text-[var(--text-tertiary)]">${escapeHtml(t('ask.sources'))}</div>
        <div class="grid gap-3">
          ${items.map((item) => `
            <a
              href="${escapeHtml(item.href || `/articles/${encodeURIComponent(item.slug)}`)}"
              class="post-card terminal-panel group relative block p-4 transition-all duration-300 hover:-translate-y-1 hover:border-[var(--primary)]"
              style="--post-border-color: var(--primary);"
            >
              <div class="absolute bottom-4 left-0 top-4 w-1 rounded-full opacity-80" style="background-color: var(--primary);"></div>

              <div class="relative z-10 mb-2 flex flex-col gap-2.5 pl-3 sm:flex-row sm:items-start sm:justify-between">
                <div class="min-w-0 flex-1">
                  <div class="mb-2 flex items-center gap-2">
                    <span class="h-3 w-3 shrink-0 rounded-full bg-[var(--primary)]"></span>
                    <span class="terminal-chip terminal-chip--accent shrink-0 px-2 py-1 text-[10px]" style="--accent-rgb: var(--primary-rgb); --accent-color: var(--primary);">
                      ${escapeHtml(t('common.article'))}
                    </span>
                    <h3 class="truncate text-base font-bold text-[var(--title-color)] transition group-hover:text-[var(--primary)]">
                      ${escapeHtml(item.title)}
                    </h3>
                  </div>
                  <p class="text-sm text-[var(--text-secondary)]">
                    ${escapeHtml(t('ask.sourceScore', { score: item.score }))}
                  </p>
                </div>

                <span class="terminal-chip shrink-0 px-2.5 py-1 text-xs">
                  #${escapeHtml(t('ask.sources'))}
                </span>
              </div>

              <p class="relative z-10 mb-3 pl-3 text-sm leading-7 text-[var(--text-secondary)]">${escapeHtml(item.excerpt)}</p>

              <div class="relative z-10 mt-3 pl-3">
                <span class="terminal-action-button inline-flex">
                  <i class="fas fa-angle-right"></i>
                  <span>${escapeHtml(t('common.readMore'))}</span>
                </span>
              </div>
            </a>
          `).join('')}
        </div>
      `;
    }

    async function readErrorMessage(response) {
      const rawText = await response.text().catch(() => '');
      if (!rawText) {
        return t('ask.requestFailed', { message: response.status });
      }

      try {
        const parsed = JSON.parse(rawText);
        return parsed.description || parsed.error || rawText;
      } catch {
        return rawText;
      }
    }

    function renderResult(data) {
      result.classList.remove('hidden');
      answer.innerHTML = renderMarkdown(data.answer);
      const relatedCount = Array.isArray(data.sources) ? data.sources.length : 0;
      meta.textContent = data.last_indexed_at
        ? t('ask.metaSourcesWithTime', { count: relatedCount, time: data.last_indexed_at })
        : t('ask.metaSources', { count: relatedCount });
      renderSources(data.sources || []);
      updatePrompt(t('ask.promptComplete', { count: relatedCount }), false);
    }

    function takeNextSseEvent(buffer) {
      const lfBoundary = buffer.indexOf('\n\n');
      const crlfBoundary = buffer.indexOf('\r\n\r\n');

      let boundaryIndex = -1;
      let separatorLength = 0;

      if (lfBoundary !== -1) {
        boundaryIndex = lfBoundary;
        separatorLength = 2;
      }

      if (crlfBoundary !== -1 && (boundaryIndex === -1 || crlfBoundary < boundaryIndex)) {
        boundaryIndex = crlfBoundary;
        separatorLength = 4;
      }

      if (boundaryIndex === -1) {
        return null;
      }

      const rawEvent = buffer.slice(0, boundaryIndex);
      const rest = buffer.slice(boundaryIndex + separatorLength);
      const normalized = rawEvent.replace(/\r\n/g, '\n');
      const lines = normalized.split('\n');
      let event = 'message';
      const dataLines = [];

      for (const line of lines) {
        if (line.startsWith('event:')) {
          event = line.slice(6).trim() || 'message';
          continue;
        }

        if (line.startsWith('data:')) {
          dataLines.push(line.slice(5).trimStart());
        }
      }

      return {
        event,
        data: dataLines.join('\n'),
        rest
      };
    }

    async function readStreamResponse(response, handlers) {
      const reader = response.body?.getReader();
      if (!reader) {
        throw new Error(t('ask.streamUnsupported'));
      }

      const decoder = new TextDecoder();
      let buffer = '';

      while (true) {
        const { value, done } = await reader.read();
        buffer += decoder.decode(value || new Uint8Array(), { stream: !done });

        while (true) {
          const parsed = takeNextSseEvent(buffer);
          if (!parsed) {
            break;
          }

          buffer = parsed.rest;

          if (!parsed.data || parsed.data === '[DONE]') {
            continue;
          }

          let payload = null;
          try {
            payload = JSON.parse(parsed.data);
          } catch {
            continue;
          }

          handlers[parsed.event]?.(payload);
        }

        if (done) {
          break;
        }
      }
    }

    async function ask(question) {
      const trimmed = String(question || '').trim();
      if (!trimmed) {
        status.textContent = t('ask.enterQuestion');
        updatePrompt(t('ask.promptIdle'));
        input?.focus();
        return;
      }

      const cached = answerCache.get(trimmed);
      if (cached) {
        renderResult(cached);
        status.textContent = t('ask.cacheRestored');
        updatePrompt(t('ask.promptComplete', { count: Array.isArray(cached.sources) ? cached.sources.length : 0 }), false);
        return;
      }

      setInteractiveState(true);
      result.classList.remove('hidden');
      answer.innerHTML = renderConnectingState(t('ask.connectingShort'));
      sources.innerHTML = '';
      meta.textContent = '';
      updatePrompt(t('ask.promptSubmitting'));

      try {
        const response = await fetch(`${apiBase}/ai/ask/stream`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ question: trimmed })
        });

        if (!response.ok) {
          throw new Error(await readErrorMessage(response));
        }

        let streamedAnswer = '';
        let completed = false;

        await readStreamResponse(response, {
          status: () => {
            status.textContent = t('ask.processing');
            updatePrompt(t('ask.promptSubmitting'), false);
          },
          delta: (payload) => {
            streamedAnswer += payload.delta || '';
            answer.innerHTML = renderMarkdown(streamedAnswer);
          },
          complete: (payload) => {
            completed = true;
            answerCache.set(trimmed, payload);
            renderResult(payload);
            status.textContent = t('ask.complete');
          },
          error: (payload) => {
            throw new Error(payload.message || t('ask.streamFailed'));
          }
        });

        if (!completed) {
          throw new Error(t('ask.streamInterrupted'));
        }
      } catch (error) {
        result.classList.remove('hidden');
        answer.innerHTML = `<p>${escapeHtml(t('ask.requestFailed', { message: error?.message || t('common.unknownError') }))}</p>`;
        meta.textContent = '';
        sources.innerHTML = '';
        status.textContent = t('ask.retryLater');
        updatePrompt(t('ask.promptFailed'), false);
      } finally {
        setInteractiveState(false);
      }
    }

    form?.addEventListener('submit', (event) => {
      event.preventDefault();
      ask(input?.value || '');
    });

    document.querySelectorAll('.sample-question').forEach((button) => {
      button.addEventListener('click', () => {
        const question = button.getAttribute('data-question') || '';
        if (input) {
          input.value = question;
        }
        updatePrompt(t('ask.promptEditing'));
        ask(question);
      });
    });

    input?.addEventListener('input', () => {
      const question = input.value.trim();
      if (!question) {
        updatePrompt(t('ask.promptIdle'), false);
        return;
      }

      updatePrompt(t('ask.promptEditing'), false);
    });

    if (prefilledQuestion) {
      if (input) {
        input.value = prefilledQuestion;
        input.focus();
      }
      status.textContent = t('ask.prefixedQuestion');
      updatePrompt(t('ask.promptEditing'), false);
    } else {
      updatePrompt(t('ask.promptIdle'), false);
    }
  </script>
)}
