---
import { resolvePublicApiBaseUrl } from '../lib/api/client';
import { terminalConfig } from '../lib/config/terminal';
import { getI18n, SUPPORTED_LOCALES } from '../lib/i18n';
import ThemeToggle from './interactive/ThemeToggle.svelte';
import type { SiteSettings } from '../lib/types';

interface Props {
  siteName?: string;
  siteSettings?: SiteSettings;
}

const {
  siteName = Astro.props.siteSettings?.siteShortName || terminalConfig.branding?.shortName || 'Termi'
} = Astro.props;

const { locale, t, buildLocaleUrl } = getI18n(Astro);
const aiEnabled = Boolean(Astro.props.siteSettings?.ai?.enabled);
const musicEnabled = Astro.props.siteSettings?.musicEnabled ?? true;
const musicPlaylist = (musicEnabled ? Astro.props.siteSettings?.musicPlaylist : []).filter(
  (item) => item?.title?.trim() && item?.url?.trim()
);
const musicPlaylistPayload = JSON.stringify(musicPlaylist);
const publicApiBaseUrl = resolvePublicApiBaseUrl(Astro.url);
const hasMusicPlaylist = musicPlaylist.length > 0;
const currentMusicTrack = hasMusicPlaylist ? musicPlaylist[0] : null;
const navItems = [
  { icon: 'fa-file-code', text: t('nav.articles'), href: '/articles' },
  { icon: 'fa-folder', text: t('nav.categories'), href: '/categories' },
  { icon: 'fa-tags', text: t('nav.tags'), href: '/tags' },
  { icon: 'fa-stream', text: t('nav.timeline'), href: '/timeline' },
  { icon: 'fa-star', text: t('nav.reviews'), href: '/reviews' },
  { icon: 'fa-link', text: t('nav.friends'), href: '/friends' },
  { icon: 'fa-user-secret', text: t('nav.about'), href: '/about' },
  ...(aiEnabled ? [{ icon: 'fa-robot', text: t('nav.ask'), href: '/ask' }] : []),
];
const localeLinks = SUPPORTED_LOCALES.map((item) => ({
  locale: item,
  href: buildLocaleUrl(item),
  label: t(`common.languages.${item}`),
  shortLabel: item === 'zh-CN' ? '中' : 'EN',
}));
const currentPath = Astro.url.pathname;
const currentNavLabel =
  navItems.find((item) => currentPath === item.href || (item.href !== '/' && currentPath.startsWith(item.href)))
    ?.text || t('header.navigation');
---

<header data-ai-search-enabled={aiEnabled ? 'true' : 'false'} class="sticky top-0 z-50 border-b border-[var(--border-color)] backdrop-blur-xl" style="background-color: color-mix(in oklab, var(--bg) 88%, transparent);">
  <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-2.5">
    <div class="terminal-toolbar-shell">
      <div class="flex flex-col gap-2.5">
        <div class="flex items-center gap-2 lg:flex-nowrap">
          <a href="/" class="terminal-toolbar-module shrink-0 min-w-[9.5rem] px-2.5 py-1.5 hover:border-[var(--primary)] transition-all">
            <span class="flex h-8 w-8 items-center justify-center rounded-xl border border-[var(--border-color)] bg-[var(--primary)]/8 text-[var(--primary)]">
              <i class="fas fa-terminal text-base"></i>
            </span>
            <span>
              <span class="terminal-toolbar-label block">{t('header.shellLabel')}</span>
              <span class="mt-0.5 block text-[15px] font-bold text-[var(--title-color)]">{siteName}</span>
            </span>
          </a>

          <div class="relative hidden min-w-[20rem] grow basis-[24rem] lg:block xl:min-w-[24rem] xl:basis-[30rem]">
            <div class="terminal-toolbar-module min-w-0 gap-2 px-2.5 py-1.5">
              <div class="terminal-toolbar-label shrink-0 whitespace-nowrap" id="search-label">{t('header.searchPromptKeyword')}</div>
              {aiEnabled && (
                <div id="search-mode-panel" class="hidden shrink-0 2xl:flex items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-1">
                  <button
                    type="button"
                    class="search-mode-btn rounded-lg px-2.5 py-1.5 text-xs font-medium text-[var(--text-secondary)] transition hover:bg-[var(--header-bg)]"
                    data-search-mode="keyword"
                    aria-pressed="true"
                  >
                    <i class="fas fa-search mr-1 text-[11px]"></i>
                    <span>{t('header.searchModeKeyword')}</span>
                  </button>
                  <button
                    type="button"
                    class="search-mode-btn rounded-lg px-2.5 py-1.5 text-xs font-medium text-[var(--text-secondary)] transition hover:bg-[var(--header-bg)]"
                    data-search-mode="ai"
                    aria-pressed="false"
                  >
                    <i class="fas fa-robot mr-1 text-[11px]"></i>
                    <span>{t('header.searchModeAi')}</span>
                  </button>
                </div>
              )}
              <input
                type="text"
                id="search-input"
                placeholder={t('header.searchPlaceholderKeyword')}
                class="terminal-console-input"
              />
              <button id="search-btn" class="terminal-toolbar-iconbtn h-8 w-8 shrink-0" aria-label="Search">
                <i id="search-btn-icon" class="fas fa-search text-sm"></i>
              </button>
            </div>
            <p id="search-hint" class="px-1 pt-0.5 text-[11px] font-mono text-[var(--text-tertiary)]">
              {t('header.searchHintKeyword')}
            </p>
            <div
              id="search-results"
              class="hidden absolute right-0 top-[calc(100%+12px)] z-20 w-[26rem] overflow-hidden rounded-2xl border border-[var(--border-color)] bg-[var(--terminal-bg)] shadow-[0_20px_40px_rgba(15,23,42,0.08)]"
            ></div>
          </div>

          <div class="ml-auto hidden shrink-0 items-center gap-2 lg:flex">
            {musicEnabled && (
              <div class="hidden 2xl:flex terminal-toolbar-module min-w-0 max-w-[13rem] gap-2 px-2.5 py-1.5">
                <div class="flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-[var(--border-color)] bg-[var(--primary)]/8">
                  <img
                    id="desktop-music-cover"
                    src={currentMusicTrack?.coverImageUrl || ''}
                    alt={currentMusicTrack?.title || 'Music cover'}
                    class:list={[
                      'h-full w-full object-cover',
                      !currentMusicTrack?.coverImageUrl && 'hidden'
                    ]}
                  />
                  <i
                    id="desktop-music-cover-fallback"
                    class:list={[
                      'fas fa-compact-disc text-sm text-[var(--primary)]',
                      currentMusicTrack?.coverImageUrl && 'hidden'
                    ]}
                  ></i>
                </div>
                <div class="min-w-0 flex-1">
                  <p class="truncate text-[13px] font-semibold text-[var(--title-color)]" id="desktop-music-title">
                    {currentMusicTrack?.title || '未配置曲目'}
                  </p>
                  <div class="mt-1 flex items-center gap-1">
                    <button id="desktop-music-prev" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Previous track" disabled={!hasMusicPlaylist}>
                      <i class="fas fa-step-backward text-[11px]"></i>
                    </button>
                    <button id="desktop-music-play" class="terminal-toolbar-iconbtn h-7 w-7 bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
                      <i class="fas fa-play text-[11px]" id="desktop-music-play-icon"></i>
                    </button>
                    <button id="desktop-music-next" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Next track" disabled={!hasMusicPlaylist}>
                      <i class="fas fa-step-forward text-[11px]"></i>
                    </button>
                  </div>
                </div>
              </div>
            )}

            {aiEnabled && (
              <a
                href="/ask"
                class="inline-flex shrink-0 items-center gap-2 rounded-xl border border-[var(--primary)]/18 bg-[var(--primary)]/8 px-2.5 py-1.5 text-sm font-medium text-[var(--primary)] transition hover:border-[var(--primary)]/32 hover:text-[var(--title-color)]"
              >
                <i class="fas fa-robot text-sm"></i>
                <span class="hidden xl:inline">{t('nav.ask')}</span>
              </a>
            )}

            <div class="flex shrink-0 items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-0.5">
              {localeLinks.map((item) => (
                <a
                  href={item.href}
                  data-locale-switch={item.locale}
                  class:list={[
                    'rounded-lg px-2.5 py-1.5 text-xs font-semibold transition',
                    item.locale === locale
                      ? 'bg-[var(--primary)] text-white shadow-sm'
                      : 'text-[var(--text-secondary)] hover:bg-[var(--header-bg)]'
                  ]}
                  aria-current={item.locale === locale ? 'true' : undefined}
                  title={item.label}
                >
                  {item.shortLabel}
                </a>
              ))}
            </div>

            <div class="relative shrink-0">
              <ThemeToggle
                client:load
                labels={{
                  toggle: t('header.themeToggle'),
                  system: t('header.themeSystem'),
                  light: t('header.themeLight'),
                  dark: t('header.themeDark'),
                }}
              />
            </div>
          </div>

          <div class="relative shrink-0 lg:hidden">
            <ThemeToggle
              client:load
              labels={{
                toggle: t('header.themeToggle'),
                system: t('header.themeSystem'),
                light: t('header.themeLight'),
                dark: t('header.themeDark'),
              }}
            />
          </div>

          <button
            id="mobile-menu-btn"
            class="terminal-toolbar-iconbtn h-9 w-9 shrink-0 lg:hidden"
            aria-label={t('header.toggleMenu')}
            aria-expanded="false"
          >
            <span class="sr-only">
              {currentNavLabel}
            </span>
            <i class="fas fa-bars text-[var(--text)]"></i>
          </button>
        </div>
    </div>
  </div>

  <!-- Mobile Menu -->
  <div id="mobile-menu" class="hidden border-t border-[var(--border-color)] bg-[var(--bg)] lg:hidden">
    <div class="px-4 py-4 space-y-4">
      <div class="grid gap-3 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]">
        <div class="space-y-3">
          <div class="space-y-3 lg:hidden">
            {aiEnabled && (
              <div class="flex items-center gap-2 rounded-2xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-1">
                <button
                  type="button"
                  class="search-mode-btn flex-1 rounded-xl px-3 py-2 text-sm font-medium text-[var(--text-secondary)] transition hover:bg-[var(--header-bg)]"
                  data-search-mode="keyword"
                  aria-pressed="true"
                >
                  <i class="fas fa-search mr-2 text-xs"></i>
                  <span>{t('header.searchModeKeywordMobile')}</span>
                </button>
                <button
                  type="button"
                  class="search-mode-btn flex-1 rounded-xl px-3 py-2 text-sm font-medium text-[var(--text-secondary)] transition hover:bg-[var(--header-bg)]"
                  data-search-mode="ai"
                  aria-pressed="false"
                >
                  <i class="fas fa-robot mr-2 text-xs"></i>
                  <span>{t('header.searchModeAiMobile')}</span>
                </button>
              </div>
            )}
            <div class="terminal-toolbar-module">
              <span class="terminal-toolbar-label" id="mobile-search-label">{t('header.searchPromptKeyword')}</span>
              <input
                type="text"
                id="mobile-search-input"
                placeholder={t('header.searchPlaceholderKeyword')}
                class="terminal-console-input"
              />
              <button id="mobile-search-btn" class="terminal-toolbar-iconbtn" aria-label="Search">
                <i id="mobile-search-btn-icon" class="fas fa-search text-sm"></i>
              </button>
            </div>
            <p id="mobile-search-hint" class="px-1 text-xs font-mono text-[var(--text-tertiary)]">{t('header.searchHintKeyword')}</p>
          </div>

          <div class="flex items-center gap-2 xl:hidden">
            <span class="terminal-toolbar-label">{t('common.language')}</span>
            <div class="flex flex-1 items-center gap-2">
              {localeLinks.map((item) => (
                <a
                  href={item.href}
                  data-locale-switch={item.locale}
                  class:list={[
                    'flex-1 rounded-xl border px-3 py-2 text-center text-sm font-medium transition',
                    item.locale === locale
                      ? 'border-[var(--primary)] bg-[var(--primary)]/10 text-[var(--primary)]'
                      : 'border-[var(--border-color)] bg-[var(--header-bg)] text-[var(--text-secondary)]'
                  ]}
                  aria-current={item.locale === locale ? 'true' : undefined}
                >
                  {item.label}
                </a>
              ))}
            </div>
          </div>
        </div>

        {musicEnabled && (
          <div class="terminal-toolbar-module items-center gap-3">
            <div class="flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-2xl border border-[var(--border-color)] bg-[var(--primary)]/8">
              <img
                id="music-cover"
                src={currentMusicTrack?.coverImageUrl || ''}
                alt={currentMusicTrack?.title || 'Music cover'}
                class:list={[
                  'h-full w-full object-cover',
                  !currentMusicTrack?.coverImageUrl && 'hidden'
                ]}
              />
              <i
                id="music-cover-fallback"
                class:list={[
                  'fas fa-compact-disc text-base text-[var(--primary)]',
                  currentMusicTrack?.coverImageUrl && 'hidden'
                ]}
              ></i>
            </div>
            <div class="min-w-0 flex-1">
              <div class="terminal-toolbar-label">{t('header.musicPanel')}</div>
              <div class="mt-1 flex items-center gap-2">
                <button id="music-prev" class="terminal-toolbar-iconbtn" aria-label="Previous track" disabled={!hasMusicPlaylist}>
                  <i class="fas fa-step-backward text-xs"></i>
                </button>
                <button id="music-play" class="terminal-toolbar-iconbtn bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
                  <i class="fas fa-play text-xs" id="music-play-icon"></i>
                </button>
                <button id="music-next" class="terminal-toolbar-iconbtn" aria-label="Next track" disabled={!hasMusicPlaylist}>
                  <i class="fas fa-step-forward text-xs"></i>
                </button>
                <button id="music-volume" class="terminal-toolbar-iconbtn" aria-label="Mute or unmute" disabled={!hasMusicPlaylist}>
                  <i class="fas fa-volume-up text-xs"></i>
                </button>
              </div>
              <div class="mt-2 min-w-0">
                <p class="truncate text-sm font-semibold text-[var(--title-color)]" id="music-title">
                  {currentMusicTrack?.title || '未配置曲目'}
                </p>
                <p class="truncate text-[11px] text-[var(--text-tertiary)]" id="music-artist">
                  {currentMusicTrack?.artist || currentMusicTrack?.album || '等待播放'}
                </p>
              </div>
            </div>
          </div>
        )}
      </div>

      <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
        {navItems.map(item => (
          <a
            href={item.href}
            class:list={[
              'terminal-nav-link',
              currentPath === item.href || (item.href !== '/' && currentPath.startsWith(item.href))
                ? 'is-active'
                : ''
            ]}
          >
            <span class="flex min-w-0 flex-1 items-center gap-3">
              <span class="flex h-10 w-10 items-center justify-center rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/82 text-[var(--primary)]">
                <i class={`fas ${item.icon} text-sm`}></i>
              </span>
              <span class="min-w-0">
                <span class="terminal-toolbar-label block">{t('header.navigation')}</span>
                <span class="mt-1 block truncate text-sm font-semibold text-[var(--title-color)]">{item.text}</span>
              </span>
            </span>
            <i class="fas fa-arrow-right text-[11px] text-[var(--text-tertiary)]"></i>
          </a>
        ))}
      </div>
    </div>
  </div>
</header>

<script is:inline define:vars={{ apiBase: publicApiBaseUrl, musicPlaylistPayload }}>
  const t = window.__termiTranslate;

  // Site Menu
  const mobileMenuBtn = document.getElementById('mobile-menu-btn');
  const mobileMenu = document.getElementById('mobile-menu');
  const mobileSearchInput = document.getElementById('mobile-search-input');
  const mobileSearchBtn = document.getElementById('mobile-search-btn');

  mobileMenuBtn?.addEventListener('click', () => {
    const nextExpanded = mobileMenu?.classList.contains('hidden');
    mobileMenu?.classList.toggle('hidden');
    mobileMenuBtn.setAttribute('aria-expanded', String(nextExpanded));
  });

  document.querySelectorAll('#mobile-menu a[href]').forEach((link) => {
    link.addEventListener('click', () => {
      mobileMenu?.classList.add('hidden');
      mobileMenuBtn?.setAttribute('aria-expanded', 'false');
    });
  });

  // Music Player with actual audio
  const musicPlay = document.getElementById('music-play');
  const musicPlayIcon = document.getElementById('music-play-icon');
  const musicCover = document.getElementById('music-cover');
  const musicCoverFallback = document.getElementById('music-cover-fallback');
  const musicTitle = document.getElementById('music-title');
  const musicArtist = document.getElementById('music-artist');
  const musicPrev = document.getElementById('music-prev');
  const musicNext = document.getElementById('music-next');
  const musicVolume = document.getElementById('music-volume');
  const desktopMusicPlay = document.getElementById('desktop-music-play');
  const desktopMusicPlayIcon = document.getElementById('desktop-music-play-icon');
  const desktopMusicCover = document.getElementById('desktop-music-cover');
  const desktopMusicCoverFallback = document.getElementById('desktop-music-cover-fallback');
  const desktopMusicTitle = document.getElementById('desktop-music-title');
  const desktopMusicPrev = document.getElementById('desktop-music-prev');
  const desktopMusicNext = document.getElementById('desktop-music-next');

  const playlist = JSON.parse(musicPlaylistPayload || '[]');

  let currentSongIndex = 0;
  let isPlaying = false;
  let audio = null;
  let volume = 0.5;

  function initAudio() {
    if (!audio) {
      audio = new Audio();
      audio.volume = volume;
      audio.addEventListener('ended', () => {
        playNext();
      });
    }
  }

  function updateTitle() {
    const currentTrack = playlist[currentSongIndex] || {};
    if (musicTitle) {
      musicTitle.textContent = currentTrack.title || '未配置曲目';
    }
    if (desktopMusicTitle) {
      desktopMusicTitle.textContent = currentTrack.title || '未配置曲目';
    }
    if (musicArtist) {
      musicArtist.textContent = currentTrack.artist || currentTrack.album || '等待播放';
    }
    if (musicCover && musicCoverFallback) {
      if (currentTrack.coverImageUrl) {
        musicCover.setAttribute('src', currentTrack.coverImageUrl);
        musicCover.setAttribute('alt', currentTrack.title || 'Music cover');
        musicCover.classList.remove('hidden');
        musicCoverFallback.classList.add('hidden');
      } else {
        musicCover.setAttribute('src', '');
        musicCover.classList.add('hidden');
        musicCoverFallback.classList.remove('hidden');
      }
    }
    if (desktopMusicCover && desktopMusicCoverFallback) {
      if (currentTrack.coverImageUrl) {
        desktopMusicCover.setAttribute('src', currentTrack.coverImageUrl);
        desktopMusicCover.setAttribute('alt', currentTrack.title || 'Music cover');
        desktopMusicCover.classList.remove('hidden');
        desktopMusicCoverFallback.classList.add('hidden');
      } else {
        desktopMusicCover.setAttribute('src', '');
        desktopMusicCover.classList.add('hidden');
        desktopMusicCoverFallback.classList.remove('hidden');
      }
    }
  }

  function playSong() {
    if (!playlist.length) {
      return;
    }
    initAudio();
    if (audio.src !== playlist[currentSongIndex].url) {
      audio.src = playlist[currentSongIndex].url;
    }
    audio.play().catch(err => console.log('Audio play failed:', err));
    isPlaying = true;
    if (musicPlayIcon) {
      musicPlayIcon.className = 'fas fa-pause text-xs';
    }
    if (desktopMusicPlayIcon) {
      desktopMusicPlayIcon.className = 'fas fa-pause text-[11px]';
    }
    if (musicTitle) {
      musicTitle.classList.add('text-[var(--primary)]');
      musicTitle.classList.remove('text-[var(--title-color)]');
    }
    if (desktopMusicTitle) {
      desktopMusicTitle.classList.add('text-[var(--primary)]');
      desktopMusicTitle.classList.remove('text-[var(--title-color)]');
    }
  }

  function pauseSong() {
    if (audio) {
      audio.pause();
    }
    isPlaying = false;
    if (musicPlayIcon) {
      musicPlayIcon.className = 'fas fa-play text-xs';
    }
    if (desktopMusicPlayIcon) {
      desktopMusicPlayIcon.className = 'fas fa-play text-[11px]';
    }
    if (musicTitle) {
      musicTitle.classList.remove('text-[var(--primary)]');
      musicTitle.classList.add('text-[var(--title-color)]');
    }
    if (desktopMusicTitle) {
      desktopMusicTitle.classList.remove('text-[var(--primary)]');
      desktopMusicTitle.classList.add('text-[var(--title-color)]');
    }
  }

  function togglePlay() {
    if (isPlaying) {
      pauseSong();
    } else {
      playSong();
    }
  }

  function playNext() {
    if (!playlist.length) {
      return;
    }
    currentSongIndex = (currentSongIndex + 1) % playlist.length;
    updateTitle();
    if (isPlaying) {
      playSong();
    }
  }

  function playPrev() {
    if (!playlist.length) {
      return;
    }
    currentSongIndex = (currentSongIndex - 1 + playlist.length) % playlist.length;
    updateTitle();
    if (isPlaying) {
      playSong();
    }
  }

  function toggleMute() {
    if (audio) {
      audio.muted = !audio.muted;
      if (musicVolume) {
        musicVolume.innerHTML = audio.muted ?
          '<i class="fas fa-volume-mute text-xs"></i>' :
          '<i class="fas fa-volume-up text-xs"></i>';
      }
    }
  }

  musicPlay?.addEventListener('click', togglePlay);
  desktopMusicPlay?.addEventListener('click', togglePlay);
  musicNext?.addEventListener('click', playNext);
  desktopMusicNext?.addEventListener('click', playNext);
  musicPrev?.addEventListener('click', playPrev);
  desktopMusicPrev?.addEventListener('click', playPrev);
  musicVolume?.addEventListener('click', toggleMute);

  // Initialize title
  updateTitle();

  // Search functionality
  const headerRoot = document.querySelector('header[data-ai-search-enabled]');
  const aiSearchEnabled = headerRoot?.getAttribute('data-ai-search-enabled') === 'true';
  const searchInput = document.getElementById('search-input');
  const searchBtn = document.getElementById('search-btn');
  const searchBtnIcon = document.getElementById('search-btn-icon');
  const searchResults = document.getElementById('search-results');
  const searchLabel = document.getElementById('search-label');
  const searchHint = document.getElementById('search-hint');
  const mobileSearchLabel = document.getElementById('mobile-search-label');
  const mobileSearchHint = document.getElementById('mobile-search-hint');
  const mobileSearchBtnIcon = document.getElementById('mobile-search-btn-icon');
  const searchModePanel = document.getElementById('search-mode-panel');
  const searchModeButtons = Array.from(document.querySelectorAll('.search-mode-btn'));
  const localeSwitchLinks = Array.from(document.querySelectorAll('[data-locale-switch]'));
  const searchApiBase = apiBase;
  const searchInputs = [searchInput, mobileSearchInput].filter(Boolean);
  const searchModeConfig = {
    keyword: {
      label: t('header.searchPromptKeyword'),
      hint: t('header.searchHintKeyword'),
      placeholder: t('header.searchPlaceholderKeyword'),
      buttonIcon: 'fa-search'
    },
    ai: {
      label: t('header.searchPromptAi'),
      hint: t('header.searchHintAi'),
      placeholder: t('header.searchPlaceholderAi'),
      buttonIcon: 'fa-robot'
    }
  };
  let searchTimer = null;
  let currentSearchMode = 'keyword';

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

  function highlightText(value, query) {
    const escapedValue = escapeHtml(value || '');
    const normalizedQuery = query.trim();
    if (!normalizedQuery) {
      return escapedValue;
    }

    const escapedQuery = normalizedQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    return escapedValue.replace(
      new RegExp(`(${escapedQuery})`, 'ig'),
      '<mark class="rounded-sm border border-[var(--border-color)] bg-[var(--primary-light)] px-1 text-[var(--title-color)]">$1</mark>'
    );
  }

  function syncSearchInputs(sourceInput) {
    const nextValue = sourceInput && 'value' in sourceInput ? sourceInput.value : '';
    searchInputs.forEach((input) => {
      if (input !== sourceInput) {
        input.value = nextValue;
      }
    });
  }

  function getQueryFromInput(input) {
    return input && 'value' in input ? input.value.trim() : '';
  }

  function buildLocalizedUrl(path) {
    const nextUrl = new URL(path, window.location.origin);
    nextUrl.searchParams.set('lang', document.documentElement.lang || 'zh-CN');
    return `${nextUrl.pathname}${nextUrl.search}${nextUrl.hash}`;
  }

  function buildSearchTarget(query) {
    return buildLocalizedUrl(
      currentSearchMode === 'ai'
        ? `/ask?q=${encodeURIComponent(query)}`
        : `/search?q=${encodeURIComponent(query)}`
    );
  }

  function syncSearchModeUI() {
    const config = searchModeConfig[currentSearchMode] || searchModeConfig.keyword;

    if (searchLabel) {
      searchLabel.textContent = config.label;
    }
    if (mobileSearchLabel) {
      mobileSearchLabel.textContent = config.label;
    }
    if (searchHint) {
      searchHint.textContent = config.hint;
    }
    if (mobileSearchHint) {
      mobileSearchHint.textContent = config.hint;
    }

    searchInputs.forEach((input) => {
      input.setAttribute('placeholder', config.placeholder);
    });

    if (searchBtnIcon) {
      searchBtnIcon.className = `fas ${config.buttonIcon} text-sm`;
    }
    if (mobileSearchBtnIcon) {
      mobileSearchBtnIcon.className = `fas ${config.buttonIcon} text-sm`;
    }

    searchModeButtons.forEach((button) => {
      const isActive = button.getAttribute('data-search-mode') === currentSearchMode;
      button.setAttribute('aria-pressed', String(isActive));
      button.classList.toggle('bg-[var(--primary)]', isActive);
      button.classList.toggle('text-white', isActive);
      button.classList.toggle('shadow-sm', isActive);
      button.classList.toggle('text-[var(--text-secondary)]', !isActive);
    });
  }

  function renderAiSearchResults(query) {
    if (!searchResults) return;

    searchResults.innerHTML = `
      <div class="overflow-hidden">
        <div class="border-b border-[var(--border-color)] px-4 py-2 text-xs uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
          ${escapeHtml(t('header.aiModeTitle'))}
        </div>
        <div class="space-y-4 px-4 py-4">
          <div class="space-y-2">
            <div class="text-sm font-semibold text-[var(--title-color)]">${escapeHtml(t('header.aiModeHeading'))}</div>
            <p class="text-sm leading-6 text-[var(--text-secondary)]">
              ${escapeHtml(t('header.aiModeDescription'))}
            </p>
            <p class="text-xs leading-5 text-[var(--text-tertiary)]">
              ${escapeHtml(t('header.aiModeNotice'))}
            </p>
          </div>
          <div class="rounded-2xl border border-[var(--border-color)] bg-[var(--bg)]/70 p-3">
            <div class="text-[11px] uppercase tracking-[0.18em] text-[var(--text-tertiary)]">${escapeHtml(t('common.search'))}</div>
            <div class="mt-2 font-mono text-sm text-[var(--title-color)]">${escapeHtml(query)}</div>
          </div>
          <a href="${buildSearchTarget(query)}" class="flex items-center justify-between rounded-2xl border border-[var(--primary)]/30 bg-[var(--primary)]/10 px-4 py-3 text-sm font-medium text-[var(--primary)] transition hover:bg-[var(--primary)]/16">
            <span><i class="fas fa-robot mr-2 text-xs"></i>${escapeHtml(t('header.aiModeCta'))}</span>
            <i class="fas fa-arrow-right text-xs"></i>
          </a>
        </div>
      </div>
    `;
    searchResults.classList.remove('hidden');
  }

  function hideSearchResults() {
    if (!searchResults) return;
    searchResults.classList.add('hidden');
    searchResults.innerHTML = '';
  }

  function renderSearchResults(query, results, state = 'ready') {
    if (!searchResults) return;

    if (state === 'loading') {
      searchResults.innerHTML = `
        <div class="px-4 py-4 text-sm text-[var(--text-secondary)]">
          ${escapeHtml(t('header.searching', { query }))} 
        </div>
      `;
      searchResults.classList.remove('hidden');
      return;
    }

    if (state === 'error') {
      searchResults.innerHTML = `
        <div class="px-4 py-4 text-sm text-[var(--danger)]">
          ${escapeHtml(t('header.searchFailed'))}
        </div>
      `;
      searchResults.classList.remove('hidden');
      return;
    }

    if (!results.length) {
      const aiRetry = aiSearchEnabled
        ? `
          <a href="${buildLocalizedUrl(`/ask?q=${encodeURIComponent(query)}`)}" class="mt-3 inline-flex items-center gap-2 rounded-full border border-[var(--primary)]/30 bg-[var(--primary)]/10 px-3 py-1.5 text-xs font-medium text-[var(--primary)] transition hover:bg-[var(--primary)]/16">
            <i class="fas fa-robot text-[11px]"></i>
            <span>${escapeHtml(t('header.searchEmptyCta'))}</span>
          </a>
        `
        : '';
      searchResults.innerHTML = `
        <div class="px-4 py-4 text-sm text-[var(--text-secondary)]">
          ${escapeHtml(t('header.searchEmpty', { query }))}
          ${aiRetry}
        </div>
      `;
      searchResults.classList.remove('hidden');
      return;
    }

    const itemsHtml = results.map((item) => {
      const tags = Array.isArray(item.tags) ? item.tags.slice(0, 4) : [];
      const tagHtml = tags.length
        ? `<div class="mt-2 flex flex-wrap gap-2">${tags
            .map((tag) => `<span class="rounded-full border border-[var(--border-color)] px-2 py-0.5 text-xs text-[var(--text-secondary)]">#${highlightText(tag, query)}</span>`)
            .join('')}</div>`
        : '';

      return `
        <a href="/articles/${encodeURIComponent(item.slug)}" class="block border-b border-[var(--border-color)] px-4 py-3 transition-colors hover:bg-[var(--header-bg)] last:border-b-0">
          <div class="flex items-center justify-between gap-3">
            <div class="text-sm font-semibold text-[var(--title-color)]">${highlightText(item.title || t('header.untitled'), query)}</div>
            <div class="text-[11px] text-[var(--text-tertiary)]">${escapeHtml(item.category || '')}</div>
          </div>
          <div class="mt-1 text-xs leading-5 text-[var(--text-secondary)]">${highlightText(item.description || item.content || '', query)}</div>
          ${tagHtml}
        </a>
      `;
    }).join('');

    const aiFooter = aiSearchEnabled
      ? `
        <a href="${buildLocalizedUrl(`/ask?q=${encodeURIComponent(query)}`)}" class="block border-t border-[var(--border-color)] px-4 py-3 text-sm font-medium text-[var(--primary)] transition-colors hover:bg-[var(--header-bg)]">
          <i class="fas fa-robot mr-2 text-xs"></i>
          ${escapeHtml(t('header.searchAiFooter'))}
        </a>
      `
      : '';

    searchResults.innerHTML = `
      <div class="max-h-[26rem] overflow-auto">
        <div class="border-b border-[var(--border-color)] px-4 py-2 text-xs uppercase tracking-[0.2em] text-[var(--text-tertiary)]">
          ${escapeHtml(t('header.liveResults'))}
        </div>
        ${itemsHtml}
        <a href="${buildLocalizedUrl(`/search?q=${encodeURIComponent(query)}`)}" class="block px-4 py-3 text-sm font-medium text-[var(--primary)] transition-colors hover:bg-[var(--header-bg)]">
          ${escapeHtml(t('header.searchAllResults'))}
        </a>
        ${aiFooter}
      </div>
    `;
    searchResults.classList.remove('hidden');
  }

  async function runLiveSearch(query) {
    if (!query) {
      hideSearchResults();
      return;
    }

    if (currentSearchMode === 'ai') {
      renderAiSearchResults(query);
      return;
    }

    renderSearchResults(query, [], 'loading');

    try {
      const response = await fetch(
        `${searchApiBase}/search?q=${encodeURIComponent(query)}&limit=6&preview=true`
      );
      if (!response.ok) {
        throw new Error(`Search failed: ${response.status}`);
      }

      const results = await response.json();
      renderSearchResults(query, Array.isArray(results) ? results : []);
    } catch (error) {
      console.error('Live search failed:', error);
      renderSearchResults(query, [], 'error');
    }
  }

  function setSearchMode(mode) {
    if (!aiSearchEnabled && mode === 'ai') {
      currentSearchMode = 'keyword';
    } else {
      currentSearchMode = mode;
    }

    syncSearchModeUI();

    const query = getQueryFromInput(searchInput);
    if (query && document.activeElement === searchInput) {
      void runLiveSearch(query);
    } else if (!query) {
      hideSearchResults();
    }
  }

  function submitSearch(preferredInput) {
    const query = getQueryFromInput(preferredInput) || getQueryFromInput(searchInput) || getQueryFromInput(mobileSearchInput);
    if (query) {
      window.location.href = buildSearchTarget(query);
    }
  }

  searchModeButtons.forEach((button) => {
    button.addEventListener('click', () => {
      const nextMode = button.getAttribute('data-search-mode') || 'keyword';
      setSearchMode(nextMode);
    });
  });

  searchBtn?.addEventListener('click', function() {
    submitSearch(searchInput);
  });
  mobileSearchBtn?.addEventListener('click', function() {
    submitSearch(mobileSearchInput);
  });

  searchInput?.addEventListener('keydown', function(e) {
    if (e.key === 'Enter') {
      e.preventDefault();
      submitSearch(searchInput);
    }
  });
  mobileSearchInput?.addEventListener('keydown', function(e) {
    if (e.key === 'Enter') {
      e.preventDefault();
      submitSearch(mobileSearchInput);
    }
  });

  searchInput?.addEventListener('input', function() {
    syncSearchInputs(searchInput);
    const query = this.value.trim();
    if (searchTimer) {
      clearTimeout(searchTimer);
    }
    searchTimer = setTimeout(() => {
      runLiveSearch(query);
    }, 180);
  });

  mobileSearchInput?.addEventListener('input', function() {
    syncSearchInputs(mobileSearchInput);
  });

  searchInput?.addEventListener('focus', function() {
    const query = this.value.trim();
    if (query) {
      runLiveSearch(query);
    }
  });

  syncSearchModeUI();

  document.addEventListener('keydown', function(event) {
    if (event.key === 'Escape') {
      mobileMenu?.classList.add('hidden');
      mobileMenuBtn?.setAttribute('aria-expanded', 'false');
      hideSearchResults();
    }
  });

  localeSwitchLinks.forEach((link) => {
    link.addEventListener('click', () => {
      const nextLocale = link.getAttribute('data-locale-switch');
      if (!nextLocale) {
        return;
      }

      localStorage.setItem('locale', nextLocale);
      document.cookie = `${'termi_locale'}=${encodeURIComponent(nextLocale)};path=/;max-age=31536000;samesite=lax`;
    });
  });

  document.addEventListener('click', function(event) {
    const target = event.target;
    if (
      searchResults &&
      !searchResults.contains(target) &&
      !searchModePanel?.contains(target) &&
      !target?.closest?.('.search-mode-btn') &&
      target !== searchInput &&
      target !== searchBtn &&
      !searchBtn?.contains(target)
    ) {
      hideSearchResults();
    }

    if (
      mobileMenu &&
      !mobileMenu.classList.contains('hidden') &&
      !mobileMenu.contains(target) &&
      !mobileMenuBtn?.contains(target)
    ) {
      mobileMenu.classList.add('hidden');
      mobileMenuBtn?.setAttribute('aria-expanded', 'false');
    }
  });
</script>
