---
import BaseLayout from '../../layouts/BaseLayout.astro';
import CommandPrompt from '../../components/ui/CommandPrompt.astro';
import { api, DEFAULT_SITE_SETTINGS, resolvePublicApiBaseUrl } from '../../lib/api/client';
import { getI18n } from '../../lib/i18n';

export const prerender = false;

let siteSettings = DEFAULT_SITE_SETTINGS;
const { locale, t } = getI18n(Astro);
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?'
    : '站长的技术栈和个人介绍是什么？'
];
---

<BaseLayout
  title={`${t('ask.pageTitle')} | ${siteSettings.siteShortName}`}
  description={t('ask.pageDescription', { siteName: siteSettings.siteName })}
  siteSettings={siteSettings}
>
  <section class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
    <div class="rounded-3xl border border-[var(--border-color)] bg-[var(--terminal-bg)] shadow-[0_28px_90px_rgba(15,23,42,0.08)] overflow-hidden">
      <div class="flex items-center justify-between gap-4 border-b border-[var(--border-color)] px-5 py-4">
        <div>
          <div class="text-xs uppercase tracking-[0.26em] text-[var(--text-tertiary)]">{t('ask.terminalLabel')}</div>
          <h1 class="mt-2 text-2xl font-bold text-[var(--title-color)]">{t('ask.title')}</h1>
          <p class="mt-2 text-sm text-[var(--text-secondary)]">{t('ask.subtitle')}</p>
        </div>
        <div class:list={[
          'rounded-full border px-3 py-1 text-xs font-mono',
          aiEnabled
            ? 'border-emerald-500/35 bg-emerald-500/10 text-emerald-600 dark:text-emerald-300'
            : 'border-amber-500/35 bg-amber-500/10 text-amber-600 dark:text-amber-300'
        ]}>
          {aiEnabled ? t('common.featureOn') : t('common.featureOff')}
        </div>
      </div>

      <div class="grid gap-8 px-5 py-6 lg:grid-cols-[minmax(0,1.5fr)_18rem]">
        <div class="min-w-0">
          {aiEnabled ? (
            <>
              <form id="ai-form" class="rounded-2xl border border-[var(--border-color)] bg-[var(--bg)]/70 p-4">
                <CommandPrompt promptId="ask-session-prompt" command={t('ask.promptIdle')} path="~/ask" />
                <textarea
                  id="ai-question"
                  class="min-h-[140px] 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="mt-4 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="mt-6 hidden rounded-2xl border border-[var(--border-color)] bg-[var(--bg)]/65 p-5">
                <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="rounded-2xl border border-dashed border-[var(--border-color)] bg-[var(--bg)]/55 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="rounded-2xl border border-[var(--border-color)] bg-[var(--bg)]/60 p-4">
            <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="rounded-2xl border border-[var(--border-color)] bg-[var(--bg)]/60 p-4">
              <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>
  </section>
</BaseLayout>

{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 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 = `<p>${escapeHtml(t('ask.connecting'))}</p>`;
      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>
)}
