import {
  type Component,
  createSignal,
  createResource,
  onMount,
  Show,
  For,
  createEffect,
} from 'solid-js';
import { Settings as SettingsIcon, Save, Plus, Trash2, Info, Download, Upload } from 'lucide-solid';
import { settingsApi } from '~/api/settings';
import { configApi } from '~/api/config';
import { apiKeysApi } from '~/api/apiKeys';
import { useI18n } from '~/i18n';
import { DEFAULT_SETTINGS, isApiError } from '~/types';
import type { UserSettings, ProviderConfig } from '~/types';
import LoadingSpinner from '~/components/ui/LoadingSpinner';
import ApiKeyManager from '~/components/ApiKeyManager';
import { getProviderInfoKey, providerSupportsWebSearch } from '~/utils/providers';

/**
 * Settings page for configuring the user's synthesis preferences.
 *
 * Key behaviors:
 * - **Export/Import**: Settings can be exported as JSON (optionally including
 *   cleartext API keys). On import, missing fields are merged with
 *   `DEFAULT_SETTINGS` so partial files are safe.
 * - **Provider auto-detection**: When only one provider is configured, the
 *   provider dropdown is hidden and that provider is auto-selected.
 * - **Rate limit null handling**: The `rate_limit_max_requests` and
 *   `rate_limit_time_window_seconds` fields accept `null` (meaning "use
 *   server defaults"). Empty inputs are stored as `null`, not zero.
 * - **Dual model state**: Research model (`ai_model`) and writing model
 *   (`ai_model_writing`) are independently selectable from the same
 *   provider's model list.
 */
const Settings: Component = () => {
  const { t } = useI18n();

  const [settings, setSettings] = createSignal<UserSettings>({
    ...DEFAULT_SETTINGS,
  });
  const [loading, setLoading] = createSignal(true);
  const [saving, setSaving] = createSignal(false);
  const [message, setMessage] = createSignal<{
    type: 'success' | 'error';
    text: string;
  } | null>(null);
  const [includeApiKeys, setIncludeApiKeys] = createSignal(false);

  const [providers] = createResource(() => configApi.listProviders());
  const [providerWarning, setProviderWarning] = createSignal(false);

  let fileInputRef: HTMLInputElement | undefined;

  onMount(async () => {
    try {
      const data = await settingsApi.get();
      setSettings(data);
    } catch (err) {
      if (isApiError(err) && err.status !== 404) {
        setMessage({ type: 'error', text: t('settings.loadError') });
      }
      // 404 means no settings yet -- use defaults
    } finally {
      setLoading(false);
    }
  });

  // Check if saved provider is still available when providers load
  createEffect(() => {
    const providerList = providers();
    const currentSettings = settings();
    if (
      providerList &&
      currentSettings.ai_provider &&
      !providerList.some(
        (p) => p.provider_name === currentSettings.ai_provider,
      )
    ) {
      setProviderWarning(true);
    }
  });

  const multipleProviders = () => (providers()?.length ?? 0) > 1;
  const singleProvider = () =>
    providers()?.length === 1 ? providers()![0] : null;

  const selectedProvider = (): ProviderConfig | undefined => {
    const providerList = providers();
    if (!providerList) return undefined;
    // If single provider, always use it
    if (providerList.length === 1) return providerList[0];
    // Otherwise, find the selected one
    return providerList.find(
      (p) => p.provider_name === settings().ai_provider,
    );
  };

  const handleProviderChange = (providerName: string) => {
    setProviderWarning(false);
    const provider = providers()?.find(
      (p) => p.provider_name === providerName,
    );
    setSettings((prev) => ({
      ...prev,
      ai_provider: providerName,
      ai_model: provider?.models[0]?.model_id ?? '',
    }));
  };

  // Auto-select the single provider if only one exists
  createEffect(() => {
    const single = singleProvider();
    if (single && !settings().ai_provider) {
      setSettings((prev) => ({
        ...prev,
        ai_provider: single.provider_name,
        ai_model: prev.ai_model || single.models[0]?.model_id || '',
      }));
    }
  });

  const handleSave = async () => {
    setSaving(true);
    setMessage(null);

    try {
      const cleanedSettings = {
        ...settings(),
        categories: settings().categories.filter((c) => c.trim() !== ''),
      };

      if (cleanedSettings.categories.length === 0) {
        cleanedSettings.categories = ['General'];
      }

      const saved = await settingsApi.update(cleanedSettings);
      setSettings(saved);
      setMessage({ type: 'success', text: t('settings.saved') });
    } catch (err) {
      if (isApiError(err)) {
        setMessage({ type: 'error', text: err.message });
      } else {
        setMessage({ type: 'error', text: t('settings.saveError') });
      }
    } finally {
      setSaving(false);
    }
  };

  const handleCategoryChange = (index: number, value: string) => {
    setSettings((prev) => {
      const newCategories = [...prev.categories];
      newCategories[index] = value;
      return { ...prev, categories: newCategories };
    });
  };

  const addCategory = () => {
    if (settings().categories.length >= 20) return;
    setSettings((prev) => ({
      ...prev,
      categories: [...prev.categories, t('settings.newCategory')],
    }));
  };

  const removeCategory = (index: number) => {
    if (settings().categories.length <= 1) return;
    setSettings((prev) => ({
      ...prev,
      categories: prev.categories.filter((_, i) => i !== index),
    }));
  };

  const handleExport = async () => {
    try {
      const exportData: Record<string, unknown> = { ...settings() };

      if (includeApiKeys()) {
        const keys = await apiKeysApi.exportKeys();
        exportData.api_keys = keys;
      }

      const blob = new Blob([JSON.stringify(exportData, null, 2)], {
        type: 'application/json',
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'settings.json';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    } catch (err) {
      if (isApiError(err)) {
        setMessage({ type: 'error', text: err.message });
      } else {
        setMessage({ type: 'error', text: t('settings.saveError') });
      }
    }
  };

  const handleImport = async (file: File) => {
    try {
      const text = await file.text();
      const data = JSON.parse(text);

      // Merge imported data over DEFAULT_SETTINGS so missing fields get defaults.
      // The spread provides defaults; explicit overrides handle the `categories`
      // field which must be validated as an array.
      const merged: UserSettings = {
        ...DEFAULT_SETTINGS,
        ...data,
        categories: Array.isArray(data.categories) ? data.categories : DEFAULT_SETTINGS.categories,
      };

      setSettings(merged);

      // Import API keys if present
      if (Array.isArray(data.api_keys)) {
        for (const key of data.api_keys) {
          if (key.provider_name && key.api_key) {
            await apiKeysApi.create({
              provider_name: key.provider_name,
              api_key: key.api_key,
            });
          }
        }
      }

      setMessage({ type: 'success', text: t('settings.importSuccess') });
    } catch {
      setMessage({ type: 'error', text: t('settings.importError') });
    }

    // Reset file input
    if (fileInputRef) {
      fileInputRef.value = '';
    }
  };

  return (
    <Show when={!loading()} fallback={<LoadingSpinner />}>
    <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
      <div class="flex items-center justify-between mb-8">
        <div class="flex items-center">
          <SettingsIcon class="h-8 w-8 text-indigo-600 mr-3" />
          <h1 class="text-3xl font-extrabold text-gray-900">
            {t('settings.title')}
          </h1>
        </div>
        <div class="flex items-center gap-2">
          {/* Export button */}
          <button
            type="button"
            onClick={handleExport}
            class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm 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-indigo-500"
            title={t('settings.export')}
          >
            <Download class="h-4 w-4 mr-1" />
            {t('settings.export')}
          </button>
          {/* Import button */}
          <button
            type="button"
            onClick={() => fileInputRef?.click()}
            class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm 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-indigo-500"
            title={t('settings.import')}
          >
            <Upload class="h-4 w-4 mr-1" />
            {t('settings.import')}
          </button>
          <input
            ref={fileInputRef}
            type="file"
            accept=".json"
            class="hidden"
            onChange={(e) => {
              const file = e.currentTarget.files?.[0];
              if (file) handleImport(file);
            }}
          />
        </div>
      </div>

      {/* Export: Include API keys checkbox */}
      <div class="mb-6">
        <label class="inline-flex items-center gap-2 cursor-pointer">
          <input
            type="checkbox"
            checked={includeApiKeys()}
            onChange={(e) => setIncludeApiKeys(e.currentTarget.checked)}
            class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
          />
          <span class="text-sm text-gray-700">{t('settings.exportIncludeKeys')}</span>
        </label>
        <Show when={includeApiKeys()}>
          <p class="mt-1 text-sm text-amber-600">
            {t('settings.exportKeysWarning')}
          </p>
        </Show>
      </div>

      <Show when={message()}>
        {(msg) => (
          <div
            class={`mb-6 p-4 rounded-md ${
              msg().type === 'success'
                ? 'bg-green-50 text-green-800 border border-green-200'
                : 'bg-red-50 text-red-800 border border-red-200'
            }`}
          >
            {msg().text}
          </div>
        )}
      </Show>

      {/* Provider unavailable warning */}
      <Show when={providerWarning()}>
        <div class="mb-6 p-4 rounded-md bg-yellow-50 text-yellow-800 border border-yellow-200">
          {t('settings.providerUnavailable')}
        </div>
      </Show>

      <div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200">
        <div class="px-4 py-5 sm:p-6 space-y-6">
          {/* Theme */}
          <div>
            <label for="theme" class="block text-sm font-medium text-gray-700">
              {t('settings.theme')}
            </label>
            <div class="mt-1">
              <input
                type="text"
                id="theme"
                class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                value={settings().theme}
                onInput={(e) =>
                  setSettings((prev) => ({
                    ...prev,
                    theme: e.currentTarget.value,
                  }))
                }
              />
            </div>
            <p class="mt-2 text-sm text-gray-500">{t('settings.themeHelp')}</p>
          </div>

          {/* Max age days + Max items per category */}
          <div class="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-2">
            <div>
              <label
                for="maxAgeDays"
                class="block text-sm font-medium text-gray-700"
              >
                {t('settings.maxAgeDays')}
              </label>
              <div class="mt-1">
                <input
                  type="number"
                  id="maxAgeDays"
                  min="1"
                  max="365"
                  class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                  value={settings().max_age_days}
                  onInput={(e) =>
                    setSettings((prev) => ({
                      ...prev,
                      max_age_days: parseInt(e.currentTarget.value) || 7,
                    }))
                  }
                />
              </div>
            </div>

            <div>
              <label
                for="maxItemsPerCategory"
                class="block text-sm font-medium text-gray-700"
              >
                {t('settings.maxItems')}
              </label>
              <div class="mt-1">
                <input
                  type="number"
                  id="maxItemsPerCategory"
                  min="1"
                  max="20"
                  class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                  value={settings().max_items_per_category}
                  onInput={(e) =>
                    setSettings((prev) => ({
                      ...prev,
                      max_items_per_category:
                        parseInt(e.currentTarget.value) || 4,
                    }))
                  }
                />
              </div>
            </div>
          </div>

          {/* Search agent behavior */}
          <div>
            <label
              for="searchAgentBehavior"
              class="block text-sm font-medium text-gray-700"
            >
              {t('settings.searchBehavior')}
            </label>
            <div class="mt-1">
              <textarea
                id="searchAgentBehavior"
                rows={3}
                class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                value={settings().search_agent_behavior}
                onInput={(e) =>
                  setSettings((prev) => ({
                    ...prev,
                    search_agent_behavior: e.currentTarget.value,
                  }))
                }
                placeholder={t('settings.searchBehaviorPlaceholder')}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500">
              {t('settings.searchBehaviorHelp')}
            </p>
          </div>

          {/* AI Provider & Model - Dynamic selection */}
          <Show
            when={providers() && providers()!.length > 0}
            fallback={
              <div>
                <label class="block text-sm font-medium text-gray-700">
                  {t('settings.model')}
                </label>
                <p class="mt-1 text-sm text-gray-400 italic">
                  {t('common.loading')}
                </p>
              </div>
            }
          >
            {/* Provider dropdown - only if multiple providers */}
            <Show when={multipleProviders()}>
              <div>
                <label
                  for="aiProvider"
                  class="block text-sm font-medium text-gray-700"
                >
                  {t('settings.provider')}
                </label>
                <div class="mt-1">
                  <select
                    id="aiProvider"
                    class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md border"
                    value={settings().ai_provider}
                    onChange={(e) =>
                      handleProviderChange(e.currentTarget.value)
                    }
                  >
                    <option value="">
                      {t('settings.providerPlaceholder')}
                    </option>
                    <For each={providers()}>
                      {(provider) => (
                        <option value={provider.provider_name}>
                          {provider.display_name}
                        </option>
                      )}
                    </For>
                  </select>
                </div>
                <p class="mt-2 text-sm text-gray-500">
                  {t('settings.providerHelp')}
                </p>
              </div>
            </Show>

            {/* Research model dropdown */}
            <div>
              <label
                for="aiModel"
                class="block text-sm font-medium text-gray-700"
              >
                {t('settings.modelResearch')}
              </label>
              <div class="mt-1">
                <select
                  id="aiModel"
                  class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md border"
                  value={settings().ai_model}
                  onChange={(e) =>
                    setSettings((prev) => ({
                      ...prev,
                      ai_model: e.currentTarget.value,
                    }))
                  }
                  disabled={!selectedProvider()}
                >
                  <Show when={!selectedProvider()}>
                    <option value="">
                      {t('settings.modelPlaceholder')}
                    </option>
                  </Show>
                  <For each={selectedProvider()?.models ?? []}>
                    {(model) => (
                      <option value={model.model_id}>
                        {model.display_name}
                      </option>
                    )}
                  </For>
                </select>
              </div>
              <p class="mt-2 text-sm text-gray-500">
                {t('settings.modelResearchHelp')}
              </p>
            </div>

            {/* Writing model dropdown */}
            <div>
              <label
                for="aiModelWriting"
                class="block text-sm font-medium text-gray-700"
              >
                {t('settings.modelWriting')}
              </label>
              <div class="mt-1">
                <select
                  id="aiModelWriting"
                  class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md border"
                  value={settings().ai_model_writing}
                  onChange={(e) =>
                    setSettings((prev) => ({
                      ...prev,
                      ai_model_writing: e.currentTarget.value,
                    }))
                  }
                  disabled={!selectedProvider()}
                >
                  <option value="">{t('settings.modelPlaceholder')}</option>
                  <For each={selectedProvider()?.models ?? []}>
                    {(model) => (
                      <option value={model.model_id}>
                        {model.display_name}
                      </option>
                    )}
                  </For>
                </select>
              </div>
              <p class="mt-2 text-sm text-gray-500">
                {t('settings.modelWritingHelp')}
              </p>
            </div>

            {/* Provider info text + web search badge */}
            <Show when={selectedProvider()}>
              {(provider) => (
                <div class="mt-3 flex items-start gap-2">
                  <Info class="h-4 w-4 text-gray-400 mt-0.5 flex-shrink-0" />
                  <div class="space-y-1">
                    <p class="text-sm text-gray-500">
                      {t(getProviderInfoKey(provider().provider_name))}
                    </p>
                    <Show
                      when={providerSupportsWebSearch(provider().provider_name)}
                      fallback={
                        <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600">
                          {t('settings.provider.noWebSearchBadge')}
                        </span>
                      }
                    >
                      <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
                        {t('settings.provider.webSearchBadge')}
                      </span>
                    </Show>
                  </div>
                </div>
              )}
            </Show>
          </Show>

          {/* Categories */}
          <div>
            <div class="flex justify-between items-center mb-4">
              <label class="block text-sm font-medium text-gray-700">
                {t('settings.categories')}
              </label>
              <button
                type="button"
                onClick={addCategory}
                disabled={settings().categories.length >= 20}
                class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
              >
                <Plus class="h-4 w-4 mr-1" />
                {t('settings.addCategory')}
              </button>
            </div>
            <div class="space-y-3">
              <For each={settings().categories}>
                {(category, index) => (
                  <div class="flex items-center gap-2">
                    <span class="text-gray-500 font-medium w-6">
                      {index() + 1}.
                    </span>
                    <input
                      type="text"
                      class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                      value={category}
                      onInput={(e) =>
                        handleCategoryChange(index(), e.currentTarget.value)
                      }
                    />
                    <button
                      type="button"
                      onClick={() => removeCategory(index())}
                      disabled={settings().categories.length <= 1}
                      class="p-2 text-red-600 hover:text-red-800 hover:bg-red-50 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
                      title={t('settings.removeCategory')}
                    >
                      <Trash2 class="h-5 w-5" />
                    </button>
                  </div>
                )}
              </For>
            </div>
          </div>

          {/* Rate Limit Section */}
          <hr class="border-gray-200" />
          <div>
            <h3 class="text-sm font-medium text-gray-700 mb-4">
              {t('settings.rateLimitSection')}
            </h3>
            <div class="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-2">
              <div>
                <label
                  for="rateLimitMaxRequests"
                  class="block text-sm font-medium text-gray-700"
                >
                  {t('settings.rateLimitMaxRequests')}
                </label>
                <div class="mt-1">
                  <input
                    type="number"
                    id="rateLimitMaxRequests"
                    min="1"
                    class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                    value={settings().rate_limit_max_requests ?? ''}
                    onInput={(e) => {
                      const val = e.currentTarget.value;
                      setSettings((prev) => ({
                        ...prev,
                        rate_limit_max_requests: val === '' ? null : (parseInt(val) || null),
                      }));
                    }}
                    placeholder=""
                  />
                </div>
              </div>

              <div>
                <label
                  for="rateLimitTimeWindow"
                  class="block text-sm font-medium text-gray-700"
                >
                  {t('settings.rateLimitTimeWindow')}
                </label>
                <div class="mt-1">
                  <input
                    type="number"
                    id="rateLimitTimeWindow"
                    min="1"
                    class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                    value={settings().rate_limit_time_window_seconds ?? ''}
                    onInput={(e) => {
                      const val = e.currentTarget.value;
                      setSettings((prev) => ({
                        ...prev,
                        rate_limit_time_window_seconds: val === '' ? null : (parseInt(val) || null),
                      }));
                    }}
                    placeholder=""
                  />
                </div>
              </div>
            </div>
            <p class="mt-2 text-sm text-gray-500">
              {t('settings.rateLimitHelp')}
            </p>
            <Show when={settings().rate_limit_max_requests !== null && settings().rate_limit_time_window_seconds !== null}>
              <p class="mt-2 text-sm text-indigo-600 font-medium">
                {t('settings.rateLimitEffective')
                  .replace('{max}', String(settings().rate_limit_max_requests))
                  .replace('{window}', String(settings().rate_limit_time_window_seconds))}
              </p>
            </Show>
            <Show when={settings().rate_limit_max_requests !== null || settings().rate_limit_time_window_seconds !== null}>
              <button
                type="button"
                onClick={() =>
                  setSettings((prev) => ({
                    ...prev,
                    rate_limit_max_requests: null,
                    rate_limit_time_window_seconds: null,
                  }))
                }
                class="mt-2 text-sm text-indigo-600 hover:text-indigo-800 underline"
              >
                {t('settings.rateLimitReset')}
              </button>
            </Show>
          </div>
        </div>

        {/* Save button */}
        <div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
          <button
            onClick={handleSave}
            disabled={saving()}
            class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
          >
            <Show
              when={!saving()}
              fallback={
                <div class="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
              }
            >
              <Save class="h-4 w-4 mr-2" />
            </Show>
            {t('settings.save')}
          </button>
        </div>
      </div>

      {/* API Key Management */}
      <Show when={providers() && providers()!.length > 0}>
        <ApiKeyManager providers={providers()!} />
      </Show>
    </div>
    </Show>
  );
};

export default Settings;

