{% extends "base.html" %}
{% block title %}{{ _("settings.title") }} - DocuElevate{% endblock %}

{# Category icon mapping #}
{% set category_icons = {
  'Core': 'fas fa-server',
  'Authentication': 'fas fa-shield-alt',
  'AI Services': 'fas fa-robot',
  'OCR Engines': 'fas fa-file-alt',
  'Storage Providers': 'fas fa-cloud-upload-alt',
  'Email': 'fas fa-envelope',
  'Watch Folders': 'fas fa-folder-open',
  'IMAP': 'fas fa-inbox',
  'Monitoring': 'fas fa-chart-line',
  'Processing': 'fas fa-cogs',
  'Notifications': 'fas fa-bell',
  'Feature Flags': 'fas fa-toggle-on',
  'UI': 'fas fa-palette',
  'PDF/A Archival': 'fas fa-archive',
  'Deduplication': 'fas fa-clone',
  'Security': 'fas fa-lock',
  'Other': 'fas fa-ellipsis-h'
} %}

{% block head_extra %}
<style>
  .setting-input { font-family: 'Courier New', monospace; }
  /* Sidebar navigation */
  .settings-sidebar { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; }
  .settings-sidebar::-webkit-scrollbar { width: 4px; }
  .settings-sidebar::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; }
  /* Category section transitions */
  .category-chevron { transition: transform 0.2s ease; }
  .category-chevron.rotate-180 { transform: rotate(180deg); }
  /* Search highlight */
  .settings-match-highlight { background-color: #fef08a; border-radius: 2px; padding: 0 2px; }
  html.dark .settings-match-highlight { background-color: #854d0e; }
  /* Smooth scroll – respect reduced-motion preference (WCAG) */
  @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
  /* No-results state */
  .settings-no-results { text-align: center; padding: 3rem 1rem; color: #9ca3af; }
</style>
{% endblock %}

{% block content %}
<div class="container mx-auto px-4 py-6" x-data="settingsApp()">
  <!-- Header -->
  <div class="mb-6">
    <div class="flex flex-col sm:flex-row justify-between items-start gap-4 mb-4">
      <div>
        <h1 class="text-3xl font-bold mb-1">{{ _("settings.page_heading") }}</h1>
        <p class="text-gray-500 text-sm">
          {{ _("settings.manage_config_prefix") }} <span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">{{ _("settings.source_db_badge") }}</span> &gt;
          <span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800 ml-1">{{ _("settings.source_env_badge") }}</span> &gt;
          <span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800 ml-1">{{ _("settings.source_default_badge") }}</span>
          <span class="mx-1.5">·</span> <span class="text-red-600">*</span> {{ _("settings.restart_required_suffix") }} <span class="mx-1.5">·</span> <i class="fas fa-lock text-xs" aria-hidden="true"></i> {{ _("settings.encrypted_suffix") }}
        </p>
      </div>
      <div class="flex items-center gap-2 flex-shrink-0">
        <a href="/setup?step=1"
           class="inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
          <i class="fas fa-magic mr-1.5" aria-hidden="true"></i> {{ _("settings.wizard_btn") }}
        </a>
        <a href="/database-wizard"
           class="inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
          <i class="fas fa-database mr-1.5" aria-hidden="true"></i> {{ _("settings.db_wizard_btn") }}
        </a>
        <div class="relative" x-data="{ exportOpen: false }">
          <button @click="exportOpen = !exportOpen"
                  class="inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
            <i class="fas fa-download mr-1.5" aria-hidden="true"></i> {{ _("settings.export_btn") }}
            <i class="fas fa-chevron-down ml-1 text-xs" aria-hidden="true"></i>
          </button>
          <div x-show="exportOpen" @click.outside="exportOpen = false" x-transition
               class="absolute right-0 mt-1 w-52 bg-white border border-gray-200 rounded-md shadow-lg z-20">
            <a href="/api/settings/export-env?source=db"
               class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
               @click="exportOpen = false">
              <i class="fas fa-database mr-2 text-green-600" aria-hidden="true"></i>{{ _("settings.export_db_only") }}
            </a>
            <a href="/api/settings/export-env?source=effective"
               class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
               @click="exportOpen = false">
              <i class="fas fa-layer-group mr-2 text-blue-600" aria-hidden="true"></i>{{ _("settings.export_full_config") }}
            </a>
          </div>
        </div>
        <a href="/admin/settings/audit-log"
           class="inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
          <i class="fas fa-history mr-1.5" aria-hidden="true"></i> {{ _("settings.audit_log_btn") }}
        </a>
      </div>
    </div>

    <!-- Search Bar -->
    <div class="relative">
      <i class="fas fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" aria-hidden="true"></i>
      <input
        type="search"
        x-model="searchQuery"
        @input="filterSettings()"
        placeholder="{{ _('settings.search_placeholder') }}"
        class="w-full pl-10 pr-20 py-2.5 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
        aria-label="{{ _('settings.search_aria_label') }}"
      />
      <div class="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2">
        <span x-show="searchQuery" x-text="matchCount + ' found'" x-transition class="text-xs text-gray-400"></span>
        <button x-show="searchQuery" @click="searchQuery = ''; filterSettings()" type="button"
                class="text-gray-400 hover:text-gray-600" aria-label="{{ _('settings.search_clear_aria') }}">
          <i class="fas fa-times"></i>
        </button>
      </div>
    </div>
  </div>

  <!-- Alert Messages -->
  <div x-show="showAlert" x-transition class="mb-4">
    <div :class="alertType === 'success' ? 'bg-green-100 border-green-500 text-green-700' : 'bg-red-100 border-red-500 text-red-700'"
         class="border-l-4 p-4 rounded-r-md" role="alert">
      <p class="font-bold" x-text="alertTitle"></p>
      <p x-text="alertMessage"></p>
    </div>
  </div>

  <!-- Two-column layout -->
  <div class="flex gap-6">
    <!-- Sidebar Navigation (hidden on small screens) -->
    <aside class="hidden lg:block w-56 flex-shrink-0" aria-label="{{ _('settings.categories_aria') }}">
      <nav class="settings-sidebar space-y-0.5 bg-white rounded-lg border border-gray-200 p-2 shadow-sm">
        <p class="px-3 py-1.5 text-xs font-semibold text-gray-400 uppercase tracking-wider">{{ _("settings.categories_heading") }}</p>
        {% for category, settings_list in settings_data.items() %}
        <button
          type="button"
          @click="scrollToCategory('{{ category|e }}')"
          class="w-full text-left px-3 py-2 rounded-md text-sm flex items-center gap-2 transition-colors hover:bg-gray-100"
          :class="activeCategory === '{{ category|e }}' ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-600'"
          data-sidebar-category="{{ category }}"
          x-show="isCategoryVisible('{{ category|e }}')"
        >
          <i class="{{ category_icons.get(category, 'fas fa-cog') }} w-4 text-center text-xs" aria-hidden="true"></i>
          <span class="truncate flex-1">{{ category }}</span>
          <span class="text-xs text-gray-400 tabular-nums" x-text="visibleCount['{{ category|e }}'] ?? {{ settings_list|length }}"></span>
        </button>
        {% endfor %}
      </nav>
    </aside>

    <!-- Main Content -->
    <div class="flex-1 min-w-0">
      <!-- Mobile category jump (visible on small screens only) -->
      <div class="lg:hidden mb-4">
        <label for="mobile-category-select" class="sr-only">{{ _("settings.jump_to_category") }}</label>
        <select id="mobile-category-select"
                @change="scrollToCategory($event.target.value)"
                class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm shadow-sm">
          <option value="">{{ _("settings.jump_to_category") }}</option>
          {% for category in settings_data.keys() %}
          <option value="{{ category }}">{{ category }} ({{ settings_data[category]|length }})</option>
          {% endfor %}
        </select>
      </div>

      <!-- No results state -->
      <div x-show="searchQuery && matchCount === 0" class="settings-no-results bg-white rounded-lg border border-gray-200 shadow-sm">
        <i class="fas fa-search text-4xl text-gray-300 mb-3"></i>
        <p class="text-gray-500 text-lg font-medium">{{ _("settings.no_results_heading") }}</p>
        <p class="text-gray-400 text-sm mt-1">{{ _("settings.no_results_hint") }} <button type="button" @click="searchQuery = ''; filterSettings()" class="text-blue-500 hover:underline">{{ _("settings.no_results_clear") }}</button></p>
      </div>

      <form @submit.prevent="saveSettings">
        {% for category, settings_list in settings_data.items() %}
        <section
          class="mb-4"
          id="category-{{ category|lower|replace(' ', '-')|replace('/', '-') }}"
          data-category="{{ category }}"
          x-show="isCategoryVisible('{{ category|e }}')"
        >
          <!-- Category Header -->
          <div
            class="flex items-center justify-between px-4 py-3 bg-white border border-gray-200 rounded-t-lg cursor-pointer hover:bg-gray-50 select-none transition-colors"
            @click="toggleCategory('{{ category|e }}')"
            role="button"
            tabindex="0"
            @keydown.enter="toggleCategory('{{ category|e }}')"
            @keydown.space.prevent="toggleCategory('{{ category|e }}')"
            :aria-expanded="openCategories['{{ category|e }}']"
            aria-controls="settings-{{ category|lower|replace(' ', '-')|replace('/', '-') }}"
          >
            <div class="flex items-center gap-3">
              <i class="{{ category_icons.get(category, 'fas fa-cog') }} text-gray-500" aria-hidden="true"></i>
              <h2 class="text-lg font-semibold text-gray-800">{{ category }}</h2>
              <span class="text-xs text-gray-400 bg-gray-100 px-2 py-0.5 rounded-full tabular-nums"
                    x-text="(visibleCount['{{ category|e }}'] ?? {{ settings_list|length }}) + ' settings'">
                {{ settings_list|length }} {{ _("settings.settings_count_suffix") }}
              </span>
            </div>
            <i class="fas fa-chevron-down text-gray-400 category-chevron"
               :class="openCategories['{{ category|e }}'] ? 'rotate-180' : ''"
               aria-hidden="true"></i>
          </div>

          <!-- Category Content -->
          <div
            x-show="openCategories['{{ category|e }}']"
            x-transition:enter="transition ease-out duration-150"
            x-transition:enter-start="opacity-0 -translate-y-1"
            x-transition:enter-end="opacity-100 translate-y-0"
            id="settings-{{ category|lower|replace(' ', '-')|replace('/', '-') }}"
            class="bg-white border border-t-0 border-gray-200 rounded-b-lg shadow-sm"
          >
            <div class="divide-y divide-gray-100">
              {% for setting in settings_list %}
              <div
                class="px-4 py-4 hover:bg-gray-50 transition-colors"
                data-setting-key="{{ setting.key }}"
                data-searchable="{{ setting.key }} {{ setting.key.replace('_', ' ') }} {{ setting.metadata.description|lower }}"
                x-show="isSettingVisible('{{ setting.key }}')"
              >
                <div class="flex justify-between items-start">
                  <div class="flex-1 min-w-0">
                    <div class="flex items-center gap-2 mb-1 flex-wrap">
                      <label for="{{ setting.key }}" class="text-sm font-medium text-gray-700">
                        {{ setting.key.replace('_', ' ').title() }}
                        {% if setting.metadata.restart_required %}
                        <span class="text-red-600" title="Restart required">*</span>
                        {% endif %}
                        {% if setting.metadata.required %}
                        <span class="text-red-600 text-xs">{{ _("settings.required_label") }}</span>
                        {% endif %}
                      </label>
                      <!-- Source Badge -->
                      <span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium
                        {% if setting.source == 'database' %}bg-green-100 text-green-800
                        {% elif setting.source == 'environment' %}bg-blue-100 text-blue-800
                        {% else %}bg-gray-100 text-gray-800{% endif %}"
                        title="Value source: {{ setting.source }}">
                        {{ setting.source_label }}
                      </span>
                      <code class="text-xs text-gray-400 hidden sm:inline">{{ setting.key }}</code>
                      <span class="sr-only sm:hidden">Key: {{ setting.key }}</span>
                    </div>

                    <p class="text-xs text-gray-500 mb-2">{{ setting.metadata.description }}</p>
                    {% if setting.metadata.get('help_link') %}
                    <p class="text-xs mb-2">
                      <a href="{{ setting.metadata.help_link }}"
                         class="text-indigo-600 hover:underline focus:outline-none focus:ring-2 focus:ring-indigo-500 rounded">
                        <i class="fas fa-external-link-alt mr-1" aria-hidden="true"></i>{{ setting.metadata.get('help_link_label', 'More info') }}
                      </a>
                    </p>
                    {% endif %}

                    {% if setting.metadata.type == 'boolean' %}
                    <!-- Boolean/Checkbox Input -->
                    <div class="flex items-center">
                      <input
                        type="checkbox"
                        id="{{ setting.key }}"
                        name="{{ setting.key }}"
                        :checked="formData['{{ setting.key }}'] === 'true' || formData['{{ setting.key }}'] === true"
                        @change="formData['{{ setting.key }}'] = $event.target.checked ? 'true' : 'false'"
                        class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
                      />
                      <label for="{{ setting.key }}" class="ml-2 text-sm text-gray-700">
                        {{ _("settings.boolean_enable_prefix") }} {{ setting.key.replace('_', ' ').title() }}
                      </label>
                    </div>
                    {% elif setting.metadata.type == 'slider' %}
                    <!-- Slider Input -->
                    <div class="flex items-center gap-4">
                      <input
                        type="range"
                        id="{{ setting.key }}"
                        name="{{ setting.key }}"
                        min="{{ setting.metadata.get('min', 0) }}"
                        max="{{ setting.metadata.get('max', 100) }}"
                        step="{{ setting.metadata.get('step', 1) }}"
                        x-model="formData['{{ setting.key }}']"
                        class="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-600"
                      />
                      <input
                        type="number"
                        min="{{ setting.metadata.get('min', 0) }}"
                        max="{{ setting.metadata.get('max', 100) }}"
                        step="{{ setting.metadata.get('step', 1) }}"
                        x-model="formData['{{ setting.key }}']"
                        class="setting-input w-24 px-2 py-1 border border-gray-300 rounded-md shadow-sm text-center focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                        aria-label="{{ setting.key.replace('_', ' ').title() }} value"
                      />
                    </div>
                    {% elif setting.metadata.type == 'multiselect' and setting.metadata.options %}
                    <!-- Multi-select checkboxes -->
                    <div class="flex flex-wrap gap-2 mt-1">
                      {% for opt in setting.metadata.options %}
                      <label class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full border cursor-pointer select-none transition-colors bg-white border-gray-300 hover:border-blue-400"
                             :class="isSelected('{{ setting.key }}', '{{ opt }}') ? 'bg-blue-100 border-blue-500 text-blue-800 font-medium' : 'text-gray-700'">
                        <input type="checkbox" class="sr-only"
                               :checked="isSelected('{{ setting.key }}', '{{ opt }}')"
                               @change="toggleMultiselect('{{ setting.key }}', '{{ opt }}', $event.target.checked)" />
                        <i :class="isSelected('{{ setting.key }}', '{{ opt }}') ? 'fas fa-check-circle text-blue-600' : 'far fa-circle text-gray-400'"></i>
                        <span class="text-sm">{{ opt }}</span>
                      </label>
                      {% endfor %}
                    </div>
                    <p class="mt-1 text-xs text-gray-400">{{ _("settings.effective_value_label") }} <code x-text="formData['{{ setting.key }}'] || '(none)'"></code></p>
                    {% elif setting.metadata.type == 'user_autocomplete' %}
                    <!-- User Autocomplete (WCAG 2.1 AA combobox pattern) -->
                    <div class="relative" x-data="userAutocomplete('{{ setting.key }}')" @click.away="showSuggestions = false">
                      <div class="relative">
                        <label for="{{ setting.key }}" class="sr-only">{{ setting.key.replace('_', ' ').title() }}</label>
                        <input
                          type="text"
                          id="{{ setting.key }}"
                          name="{{ setting.key }}"
                          x-model="formData['{{ setting.key }}']"
                          @input.debounce.250ms="fetchSuggestions($event.target.value)"
                          @focus="if (formData['{{ setting.key }}']) fetchSuggestions(formData['{{ setting.key }}']); else fetchSuggestions('')"
                          @keydown.arrow-down.prevent="highlightNext()"
                          @keydown.arrow-up.prevent="highlightPrev()"
                          @keydown.enter.prevent="selectHighlighted()"
                          @keydown.escape="showSuggestions = false"
                          class="setting-input w-full px-3 py-2 pl-9 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                          placeholder="{{ _('settings.user_autocomplete_placeholder') }}"
                          autocomplete="off"
                          role="combobox"
                          aria-autocomplete="list"
                          aria-label="{{ setting.key.replace('_', ' ').title() }} — search existing users"
                          :aria-expanded="showSuggestions && suggestions.length > 0"
                          aria-haspopup="listbox"
                          :aria-controls="'{{ setting.key }}_listbox'"
                          :aria-activedescendant="highlightedIdx >= 0 ? '{{ setting.key }}_opt_' + highlightedIdx : ''"
                        />
                        <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
                          <i class="fas fa-user text-gray-400 text-sm" aria-hidden="true"></i>
                        </div>
                        <div x-show="loading" class="absolute inset-y-0 right-0 flex items-center pr-3" aria-hidden="true">
                          <i class="fas fa-spinner fa-spin text-gray-400 text-sm"></i>
                        </div>
                      </div>
                      <!-- Live region for screen reader announcements -->
                      <div class="sr-only" aria-live="polite" aria-atomic="true" x-text="statusText"></div>
                      <!-- Suggestion dropdown -->
                      <ul
                        x-show="showSuggestions && suggestions.length > 0"
                        x-transition:enter="transition ease-out duration-100"
                        x-transition:enter-start="opacity-0 -translate-y-1"
                        x-transition:enter-end="opacity-100 translate-y-0"
                        class="absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg max-h-48 overflow-y-auto"
                        role="listbox"
                        :id="'{{ setting.key }}_listbox'"
                        :aria-label="'{{ setting.key.replace('_', ' ').title() }} suggestions'"
                      >
                        <template x-for="(user, idx) in suggestions" :key="user">
                          <li
                            :id="'{{ setting.key }}_opt_' + idx"
                            role="option"
                            :aria-selected="highlightedIdx === idx"
                            @mouseenter="highlightedIdx = idx"
                            @click="selectUser(user)"
                            class="px-3 py-2.5 text-sm cursor-pointer flex items-center gap-2 min-h-[44px]"
                            :class="highlightedIdx === idx ? 'bg-blue-50 text-blue-700' : 'text-gray-700 hover:bg-gray-50'"
                          >
                            <i class="fas fa-user-circle text-gray-400" aria-hidden="true"></i>
                            <span x-text="user"></span>
                          </li>
                        </template>
                      </ul>
                      <!-- Empty state -->
                      <div
                        x-show="showSuggestions && suggestions.length === 0 && !loading && searchDone"
                        class="absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg px-3 py-2 text-sm text-gray-500"
                        role="status"
                      >
                        <i class="fas fa-info-circle mr-1" aria-hidden="true"></i> {{ _("settings.user_autocomplete_empty") }}
                      </div>
                      <p class="text-xs text-gray-400 mt-1" id="{{ setting.key }}_help">
                        <i class="fas fa-info-circle mr-1" aria-hidden="true"></i>
                        {{ _("settings.user_autocomplete_hint") }}
                      </p>
                    </div>
                    {% elif setting.metadata.type == 'autocomplete' %}
                    <!-- Dynamic Autocomplete (WCAG 2.1 AA combobox pattern) -->
                    <div class="relative" x-data="dynamicAutocomplete('{{ setting.key }}')" @click.away="showSuggestions = false">
                      <div class="relative">
                        <label for="{{ setting.key }}" class="sr-only">{{ setting.key.replace('_', ' ').title() }}</label>
                        <input
                          type="text"
                          id="{{ setting.key }}"
                          name="{{ setting.key }}"
                          x-model="formData['{{ setting.key }}']"
                          @input.debounce.200ms="fetchSuggestions($event.target.value)"
                          @focus="fetchSuggestions(formData['{{ setting.key }}'] || '')"
                          @keydown.arrow-down.prevent="highlightNext()"
                          @keydown.arrow-up.prevent="highlightPrev()"
                          @keydown.enter.prevent="selectHighlighted()"
                          @keydown.escape="showSuggestions = false"
                          class="setting-input w-full px-3 py-2 pl-9 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                          placeholder="{{ _('settings.autocomplete_placeholder') }}"
                          autocomplete="off"
                          role="combobox"
                          aria-autocomplete="list"
                          aria-label="{{ setting.key.replace('_', ' ').title() }} — type to search suggestions"
                          :aria-expanded="showSuggestions && filtered.length > 0"
                          aria-haspopup="listbox"
                          :aria-controls="'{{ setting.key }}_listbox'"
                          :aria-activedescendant="highlightedIdx >= 0 ? '{{ setting.key }}_opt_' + highlightedIdx : ''"
                        />
                        <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
                          <i class="fas fa-search text-gray-400 text-sm" aria-hidden="true"></i>
                        </div>
                        <div x-show="loading" class="absolute inset-y-0 right-0 flex items-center pr-3" aria-hidden="true">
                          <i class="fas fa-spinner fa-spin text-gray-400 text-sm"></i>
                        </div>
                      </div>
                      <!-- Live region for screen reader announcements -->
                      <div class="sr-only" aria-live="polite" aria-atomic="true" x-text="statusText"></div>
                      <!-- Suggestion dropdown -->
                      <ul
                        x-show="showSuggestions && filtered.length > 0"
                        x-transition:enter="transition ease-out duration-100"
                        x-transition:enter-start="opacity-0 -translate-y-1"
                        x-transition:enter-end="opacity-100 translate-y-0"
                        class="absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg max-h-48 overflow-y-auto"
                        role="listbox"
                        :id="'{{ setting.key }}_listbox'"
                        :aria-label="'{{ setting.key.replace('_', ' ').title() }} suggestions'"
                      >
                        <template x-for="(item, idx) in filtered" :key="item">
                          <li
                            :id="'{{ setting.key }}_opt_' + idx"
                            role="option"
                            :aria-selected="highlightedIdx === idx"
                            @mouseenter="highlightedIdx = idx"
                            @click="selectItem(item)"
                            class="px-3 py-2.5 text-sm cursor-pointer min-h-[44px] flex items-center"
                            :class="highlightedIdx === idx ? 'bg-blue-50 text-blue-700' : 'text-gray-700 hover:bg-gray-50'"
                          >
                            <span x-text="item"></span>
                          </li>
                        </template>
                      </ul>
                      <!-- Empty state -->
                      <div
                        x-show="showSuggestions && filtered.length === 0 && !loading && searchDone"
                        class="absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg px-3 py-2 text-sm text-gray-500"
                        role="status"
                      >
                        <i class="fas fa-info-circle mr-1" aria-hidden="true"></i> {{ _("settings.autocomplete_no_matches") }}
                      </div>
                      <p class="text-xs text-gray-400 mt-1">
                        <i class="fas fa-info-circle mr-1" aria-hidden="true"></i>
                        {{ _("settings.autocomplete_hint") }}
                      </p>
                    </div>
                    {% elif setting.metadata.type == 'model_picker' %}
                    <!-- Model Picker -->
                    <div class="relative">
                      <input
                        type="text"
                        id="{{ setting.key }}"
                        name="{{ setting.key }}"
                        list="{{ setting.key }}_models"
                        x-model="formData['{{ setting.key }}']"
                        class="setting-input w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                        placeholder="{{ _('settings.model_picker_placeholder') }}"
                        autocomplete="off"
                      />
                      <datalist id="{{ setting.key }}_models">
                        {% for m in setting.metadata.suggested_models %}
                        <option value="{{ m }}">{{ m }}</option>
                        {% endfor %}
                      </datalist>
                      <p class="text-xs text-gray-400 mt-1">
                        <i class="fas fa-info-circle mr-1" aria-hidden="true"></i>
                        {{ _("settings.model_picker_hint") }}
                      </p>
                    </div>
                    {% elif setting.metadata.options %}
                    <!-- Dropdown Select -->
                    <select
                      id="{{ setting.key }}"
                      name="{{ setting.key }}"
                      x-model="formData['{{ setting.key }}']"
                      class="setting-input w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                    >
                      <option value="">{{ _("common.select_placeholder") }}</option>
                      {% for opt in setting.metadata.options %}
                      <option value="{{ opt }}">{{ opt }}</option>
                      {% endfor %}
                    </select>
                    {% else %}
                    <!-- Text / Password Input -->
                    <div class="relative">
                      {% if setting.metadata.sensitive %}
                      <div class="relative">
                        <input
                          :type="showPassword['{{ setting.key }}'] ? 'text' : 'password'"
                          id="{{ setting.key }}"
                          name="{{ setting.key }}"
                          x-model="formData['{{ setting.key }}']"
                          class="setting-input w-full px-3 py-2 pr-24 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 font-mono text-sm"
                          placeholder="{{ setting.metadata.description }}"
                          autocomplete="off"
                        />
                        <div class="absolute inset-y-0 right-0 flex items-center pr-3 space-x-2">
                          <span class="text-xs text-gray-400" title="{{ _('settings.encrypted_title') }}">
                            <i class="fas fa-lock"></i>
                          </span>
                          <button
                            type="button"
                            @click="togglePassword('{{ setting.key }}')"
                            class="text-gray-400 hover:text-gray-600 focus:outline-none"
                            title="{{ _('settings.toggle_visibility_title') }}"
                            aria-label="{{ _('settings.toggle_visibility_aria') }}"
                          >
                            <i :class="showPassword['{{ setting.key }}'] ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
                          </button>
                        </div>
                      </div>
                      {% else %}
                      <input
                        type="text"
                        id="{{ setting.key }}"
                        name="{{ setting.key }}"
                        x-model="formData['{{ setting.key }}']"
                        class="setting-input w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
                        placeholder="{{ setting.metadata.description }}"
                      />
                      {% endif %}
                    </div>
                    {% endif %}
                  </div>

                  <!-- Per-setting actions -->
                  <div class="ml-4 flex-shrink-0 flex flex-row items-center gap-2 pt-1">
                    <button
                      type="button"
                      x-show="isDbOverride['{{ setting.key }}']"
                      x-transition
                      @click="revertSetting('{{ setting.key }}')"
                      :disabled="revertingKey === '{{ setting.key }}'"
                      class="px-3 py-1 text-sm bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap"
                      title="{{ _('settings.revert_title') }}"
                    >
                      <span x-show="revertingKey !== '{{ setting.key }}'"><i class="fas fa-trash-alt mr-1" aria-hidden="true"></i>{{ _("settings.revert_btn") }}</span>
                      <span x-show="revertingKey === '{{ setting.key }}'">{{ _("settings.reverting") }}</span>
                    </button>
                    <button
                      type="button"
                      x-show="formData['{{ setting.key }}'] !== originalData['{{ setting.key }}']"
                      x-transition
                      @click="saveSetting('{{ setting.key }}')"
                      :disabled="savingKey === '{{ setting.key }}'"
                      class="px-3 py-1 text-sm bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap"
                      title="{{ _('settings.save_setting_title') }}"
                    >
                      <span x-show="savingKey !== '{{ setting.key }}'"><i class="fas fa-save mr-1" aria-hidden="true"></i>{{ _("common.save") }}</span>
                      <span x-show="savingKey === '{{ setting.key }}'">{{ _("settings.saving_state") }}</span>
                    </button>
                  </div>
                </div>
              </div>
              {% endfor %}
            </div>
          </div>
        </section>
        {% endfor %}

        <!-- Bulk Action Buttons -->
        <div class="flex justify-end space-x-4 mt-6" x-show="!searchQuery">
          <button
            type="button"
            @click="resetForm"
            class="px-6 py-2 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
          >
            {{ _("common.reset") }}
          </button>
          <button
            type="submit"
            :disabled="saving"
            class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <span x-show="!saving">{{ _("settings.save_all_btn") }}</span>
            <span x-show="saving">{{ _("settings.saving_state") }}</span>
          </button>
        </div>
      </form>
    </div>
  </div>
</div>

<script>
function settingsApp() {
  return {
    formData: {},
    originalData: {},
    isDbOverride: {},
    showPassword: {},
    saving: false,
    savingKey: null,
    revertingKey: null,
    showAlert: false,
    alertType: 'success',
    alertTitle: '',
    alertMessage: '',
    searchQuery: '',
    matchCount: 0,
    activeCategory: '',
    openCategories: {},
    visibleSettings: {},
    visibleCount: {},
    allCategories: [],
    settingSearchIndex: {},

    init() {
      const categories = [];
      {% for category, settings_list in settings_data.items() %}
        categories.push('{{ category|e }}');
        this.openCategories['{{ category|e }}'] = true;
        this.visibleCount['{{ category|e }}'] = {{ settings_list|length }};
        {% for setting in settings_list %}
          this.formData['{{ setting.key }}'] = {{ setting.display_value|tojson }};
          this.originalData['{{ setting.key }}'] = {{ setting.display_value|tojson }};
          this.isDbOverride['{{ setting.key }}'] = {{ (setting.source == 'database')|tojson }};
          this.showPassword['{{ setting.key }}'] = false;
          this.visibleSettings['{{ setting.key }}'] = true;
          this.settingSearchIndex['{{ setting.key }}'] = {
            category: '{{ category|e }}',
            searchText: {{ (setting.key ~ ' ' ~ setting.key.replace('_', ' ') ~ ' ' ~ setting.metadata.description)|lower|tojson }}
          };
        {% endfor %}
      {% endfor %}
      this.allCategories = categories;
      if (categories.length > 0) this.activeCategory = categories[0];

      // Set up intersection observer for active category tracking
      this.$nextTick(() => {
        const observer = new IntersectionObserver((entries) => {
          for (const entry of entries) {
            if (entry.isIntersecting) {
              const cat = entry.target.getAttribute('data-category');
              if (cat) this.activeCategory = cat;
            }
          }
        }, { rootMargin: '-20% 0px -70% 0px' });

        document.querySelectorAll('[data-category]').forEach(el => observer.observe(el));

        // Clean up observer when component is destroyed
        if (this.$cleanup) {
          this.$cleanup(() => observer.disconnect());
        }
      });
    },

    /** Filter settings based on search query. */
    filterSettings() {
      const query = this.searchQuery.toLowerCase().trim();
      let totalMatches = 0;

      for (const cat of this.allCategories) {
        this.visibleCount[cat] = 0;
      }

      for (const [key, index] of Object.entries(this.settingSearchIndex)) {
        if (!query) {
          this.visibleSettings[key] = true;
          this.visibleCount[index.category]++;
        } else {
          const matches = index.searchText.includes(query);
          this.visibleSettings[key] = matches;
          if (matches) {
            totalMatches++;
            this.visibleCount[index.category]++;
          }
        }
      }
      this.matchCount = totalMatches;

      // When searching, auto-expand categories with matches and collapse empty ones
      if (query) {
        for (const cat of this.allCategories) {
          this.openCategories[cat] = this.visibleCount[cat] > 0;
        }
      }
    },

    /** Check if a category has any visible settings. */
    isCategoryVisible(category) {
      if (!this.searchQuery) return true;
      return (this.visibleCount[category] || 0) > 0;
    },

    /** Check if a single setting is visible (matches search). */
    isSettingVisible(key) {
      if (!this.searchQuery) return true;
      return this.visibleSettings[key] === true;
    },

    /** Toggle a category open/closed. */
    toggleCategory(category) {
      this.openCategories[category] = !this.openCategories[category];
    },

    /** Scroll to a category section. */
    scrollToCategory(category) {
      this.activeCategory = category;
      // Open the category if closed
      this.openCategories[category] = true;
      const slug = category.toLowerCase().replace(/ /g, '-').replace(/\//g, '-');
      const el = document.getElementById('category-' + slug);
      if (el) {
        el.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }
    },

    /** Parse a comma-separated multiselect value into a trimmed array. */
    parseMultiselect(key) {
      return (this.formData[key] || '').split(',').map(s => s.trim()).filter(Boolean);
    },

    /** Return true when *option* is present in the comma-separated *key* value. */
    isSelected(key, option) {
      return this.parseMultiselect(key).includes(option);
    },

    /** Add or remove *option* from the comma-separated *key* value. */
    toggleMultiselect(key, option, checked) {
      const current = this.parseMultiselect(key);
      if (checked) {
        if (!current.includes(option)) current.push(option);
      } else {
        const idx = current.indexOf(option);
        if (idx !== -1) current.splice(idx, 1);
      }
      this.formData[key] = current.join(',');
    },

    togglePassword(key) {
      this.showPassword[key] = !this.showPassword[key];
    },

    resetForm() {
      this.formData = { ...this.originalData };
      this.hideAlert();
    },

    showSuccessAlert(title, message) {
      this.alertType = 'success';
      this.alertTitle = title;
      this.alertMessage = message;
      this.showAlert = true;
      setTimeout(() => this.hideAlert(), 5000);
    },

    showErrorAlert(title, message) {
      this.alertType = 'error';
      this.alertTitle = title;
      this.alertMessage = message;
      this.showAlert = true;
      setTimeout(() => this.hideAlert(), 10000);
    },

    hideAlert() {
      this.showAlert = false;
    },

    async saveSetting(key) {
      this.savingKey = key;
      this.hideAlert();

      try {
        const value = this.formData[key];
        const response = await fetch(`/api/settings/${key}`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ key, value }),
        });

        const result = await response.json();

        if (response.ok && result.success) {
          this.originalData[key] = value;
          this.isDbOverride[key] = true;
          let message = `Setting '${key}' saved successfully.`;
          if (result.restart_required) {
            message += ' Please restart the application for this change to take effect.';
          }
          this.showSuccessAlert('Setting Saved', message);
        } else {
          this.showErrorAlert('Save Failed', result.detail || 'Unknown error');
        }
      } catch (error) {
        console.error('Error saving setting:', error);
        this.showErrorAlert('Error', 'Failed to save setting. Please try again.');
      } finally {
        this.savingKey = null;
      }
    },

    async revertSetting(key) {
      if (!confirm(`Remove '${key}' from the database?\n\nThe setting will revert to its environment variable or default value.`)) {
        return;
      }

      this.revertingKey = key;
      this.hideAlert();

      try {
        const response = await fetch(`/api/settings/${key}`, {
          method: 'DELETE',
        });

        if (response.ok) {
          window.location.reload();
        } else {
          const result = await response.json();
          this.showErrorAlert('Revert Failed', result.detail || 'Unknown error');
          this.revertingKey = null;
        }
      } catch (error) {
        console.error('Error reverting setting:', error);
        this.showErrorAlert('Error', 'Failed to revert setting. Please try again.');
        this.revertingKey = null;
      }
    },

    async saveSettings() {
      this.saving = true;
      this.hideAlert();

      try {
        const updates = [];
        for (const [key, value] of Object.entries(this.formData)) {
          if (value !== this.originalData[key]) {
            updates.push({ key, value });
          }
        }

        if (updates.length === 0) {
          this.showSuccessAlert('No Changes', 'No settings were modified.');
          this.saving = false;
          return;
        }

        const response = await fetch('/api/settings/bulk-update', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(updates),
        });

        const result = await response.json();

        if (response.ok && result.success) {
          for (const updated of result.updated) {
            this.originalData[updated.key] = updated.value;
            this.isDbOverride[updated.key] = true;
          }
          let message = `${result.updated.length} setting(s) updated successfully.`;
          if (result.restart_required) {
            message += ' Please restart the application for changes to take effect.';
          }
          this.showSuccessAlert('Settings Saved', message);
        } else {
          const errorMessages = result.errors ? result.errors.map(e => `${e.key}: ${e.error}`).join(', ') : 'Unknown error';
          this.showErrorAlert('Save Failed', errorMessages);
        }
      } catch (error) {
        console.error('Error saving settings:', error);
        this.showErrorAlert('Error', 'Failed to save settings. Please try again.');
      } finally {
        this.saving = false;
      }
    }
  };
}

/**
 * Alpine.js component for the user-autocomplete setting widget.
 * Implements the ARIA 1.1 combobox pattern (WCAG 2.1 AA).
 * Fetches matching owner_id values from GET /api/users/search?q=<term>&limit=5
 * and displays them in a dropdown list.
 */
function userAutocomplete(settingKey) {
  return {
    suggestions: [],
    showSuggestions: false,
    loading: false,
    searchDone: false,
    highlightedIdx: -1,
    statusText: '',

    async fetchSuggestions(query) {
      this.loading = true;
      this.searchDone = false;
      this.highlightedIdx = -1;
      this.statusText = 'Searching…';
      try {
        const resp = await fetch('/api/users/search?q=' + encodeURIComponent(query || '') + '&limit=5');
        if (resp.ok) {
          const data = await resp.json();
          this.suggestions = data.users || [];
        } else {
          this.suggestions = [];
        }
      } catch {
        this.suggestions = [];
      }
      this.loading = false;
      this.searchDone = true;
      this.showSuggestions = true;
      // Announce result count to screen readers via live region
      if (this.suggestions.length === 0) {
        this.statusText = 'No matching users found';
      } else if (this.suggestions.length === 1) {
        this.statusText = '1 user found';
      } else {
        this.statusText = this.suggestions.length + ' users found';
      }
    },

    selectUser(user) {
      this.formData[settingKey] = user;
      this.showSuggestions = false;
      this.statusText = user + ' selected';
    },

    highlightNext() {
      if (this.suggestions.length === 0) return;
      this.highlightedIdx = (this.highlightedIdx + 1) % this.suggestions.length;
      this.statusText = this.suggestions[this.highlightedIdx];
    },

    highlightPrev() {
      if (this.suggestions.length === 0) return;
      this.highlightedIdx = this.highlightedIdx <= 0 ? this.suggestions.length - 1 : this.highlightedIdx - 1;
      this.statusText = this.suggestions[this.highlightedIdx];
    },

    selectHighlighted() {
      if (this.highlightedIdx >= 0 && this.highlightedIdx < this.suggestions.length) {
        this.selectUser(this.suggestions[this.highlightedIdx]);
      } else {
        this.showSuggestions = false;
      }
    }
  };
}

/**
 * Alpine.js component for the generic dynamic autocomplete setting widget.
 * Fetches suggestions from GET /api/settings/{key}/suggestions?q=<term>&limit=10
 * using a debounced API call.  Implements the ARIA 1.1 combobox pattern.
 */
function dynamicAutocomplete(settingKey) {
  return {
    filtered: [],
    showSuggestions: false,
    loading: false,
    searchDone: false,
    highlightedIdx: -1,
    statusText: '',

    async fetchSuggestions(query) {
      this.loading = true;
      this.searchDone = false;
      this.highlightedIdx = -1;
      this.statusText = 'Searching…';
      try {
        const resp = await fetch('/api/settings/' + encodeURIComponent(settingKey) + '/suggestions?q=' + encodeURIComponent(query || '') + '&limit=10');
        if (resp.ok) {
          const data = await resp.json();
          this.filtered = data.suggestions || [];
        } else {
          this.filtered = [];
        }
      } catch {
        this.filtered = [];
      }
      this.loading = false;
      this.searchDone = true;
      this.showSuggestions = true;
      if (this.filtered.length === 0) {
        this.statusText = 'No matches found';
      } else if (this.filtered.length === 1) {
        this.statusText = '1 suggestion found';
      } else {
        this.statusText = this.filtered.length + ' suggestions found';
      }
    },

    selectItem(item) {
      this.formData[settingKey] = item;
      this.showSuggestions = false;
      this.statusText = item + ' selected';
    },

    highlightNext() {
      if (this.filtered.length === 0) return;
      this.highlightedIdx = (this.highlightedIdx + 1) % this.filtered.length;
      this.statusText = this.filtered[this.highlightedIdx];
    },

    highlightPrev() {
      if (this.filtered.length === 0) return;
      this.highlightedIdx = this.highlightedIdx <= 0 ? this.filtered.length - 1 : this.highlightedIdx - 1;
      this.statusText = this.filtered[this.highlightedIdx];
    },

    selectHighlighted() {
      if (this.highlightedIdx >= 0 && this.highlightedIdx < this.filtered.length) {
        this.selectItem(this.filtered[this.highlightedIdx]);
      } else {
        this.showSuggestions = false;
      }
    }
  };
}
</script>
{% endblock %}
