import {
  type Component,
  createSignal,
  createEffect,
  onMount,
  onCleanup,
  Show,
  For,
} from 'solid-js';
import {
  Plus,
  Trash2,
  Link as LinkIcon,
  Download,
  Upload,
  Save,
  Star,
} from 'lucide-solid';
import Button from '~/components/ui/Button';
import { themesApi } from '~/api/themes';
import type { ThemeResponse, CreateThemeRequest, UpdateThemeRequest } from '~/api/themes';
import { sourcesApi } from '~/api/sources';
import { normalizeUrl, isValidUrl } from '~/utils/url';
import { useI18n } from '~/i18n';
import { isApiError } from '~/types';
import type { Source } from '~/types';
import LoadingSpinner from '~/components/ui/LoadingSpinner';
import SettingsSchedule from '~/components/settings/SettingsSchedule';

/**
 * Theme management page ("Personnaliser les syntheses").
 *
 * Replaces the standalone Sources page by grouping sources under user-defined
 * themes. Each theme carries its own content settings (search topic,
 * categories, age, item count, summary length) and an associated set of
 * custom sources.
 */
const ThemeManager: Component = () => {
  const { t } = useI18n();

  // ---- Theme list state ----
  const [themes, setThemes] = createSignal<ThemeResponse[]>([]);
  const [loading, setLoading] = createSignal(true);
  const [selectedThemeId, setSelectedThemeId] = createSignal<string | null>(null);

  // ---- Editing state for the selected theme's content settings ----
  const [editName, setEditName] = createSignal('');
  const [editThemeTopic, setEditThemeTopic] = createSignal('');
  const [editCategories, setEditCategories] = createSignal<string[]>([]);
  const [editMaxAge, setEditMaxAge] = createSignal(7);
  const [editMaxItems, setEditMaxItems] = createSignal(5);
  const [editSummaryLength, setEditSummaryLength] = createSignal(2);
  const [newCategory, setNewCategory] = createSignal('');
  const [savingTheme, setSavingTheme] = createSignal(false);
  const [themeMessage, setThemeMessage] = createSignal<{
    type: 'success' | 'error';
    text: string;
  } | null>(null);

  // ---- Creating a new theme ----
  const [creating, setCreating] = createSignal(false);

  // ---- Delete theme ----
  const [confirmingDeleteTheme, setConfirmingDeleteTheme] = createSignal(false);
  let deleteThemeTimer: ReturnType<typeof setTimeout> | undefined;

  // ---- Sources state ----
  const [sources, setSources] = createSignal<Source[]>([]);
  const [loadingSources, setLoadingSources] = createSignal(false);
  const [newTitle, setNewTitle] = createSignal('');
  const [newUrl, setNewUrl] = createSignal('');
  const [adding, setAdding] = createSignal(false);
  const [addError, setAddError] = createSignal<string | null>(null);
  const [bulkText, setBulkText] = createSignal('');
  const [importing, setImporting] = createSignal(false);
  const [importError, setImportError] = createSignal<string | null>(null);
  const [csvError, setCsvError] = createSignal<string | null>(null);
  const [confirmingDeleteId, setConfirmingDeleteId] = createSignal<string | null>(null);

  let deleteTimer: ReturnType<typeof setTimeout> | undefined;
  let fileInputRef: HTMLInputElement | undefined;

  onCleanup(() => {
    if (deleteTimer) clearTimeout(deleteTimer);
    if (deleteThemeTimer) clearTimeout(deleteThemeTimer);
  });

  // ---- Computed: selected theme from list ----
  const selectedTheme = (): ThemeResponse | null => {
    const id = selectedThemeId();
    if (!id) return null;
    return themes().find((th) => th.id === id) ?? null;
  };

  // ---- Load themes ----
  const fetchThemes = async () => {
    try {
      const data = await themesApi.list();
      setThemes(data);
    } catch (err) {
      console.error('Failed to load themes:', err);
    } finally {
      setLoading(false);
    }
  };

  onMount(fetchThemes);

  // ---- Load sources for selected theme ----
  const fetchSources = async (themeId: string) => {
    setLoadingSources(true);
    try {
      const data = await sourcesApi.list(themeId);
      setSources(data);
    } catch (err) {
      console.error('Failed to load sources:', err);
    } finally {
      setLoadingSources(false);
    }
  };

  // ---- When a theme is selected, populate editing state + load sources ----
  createEffect(() => {
    const theme = selectedTheme();
    if (theme) {
      setEditName(theme.name);
      setEditThemeTopic(theme.theme);
      setEditCategories([...theme.categories]);
      setEditMaxAge(theme.max_age_days);
      setEditMaxItems(theme.max_items_per_category);
      setEditSummaryLength(theme.summary_length);
      setThemeMessage(null);
      setConfirmingDeleteTheme(false);
      fetchSources(theme.id);
    } else {
      setSources([]);
    }
  });

  // ---- Create new theme ----
  const handleCreateTheme = async () => {
    setCreating(true);
    try {
      const data: CreateThemeRequest = {
        name: t('themes.createTheme'),
        theme: t('themes.createTheme'),
        categories: [t('themes.defaultCategory')],
      };
      const created = await themesApi.create(data);
      setThemes((prev) => [...prev, created]);
      setSelectedThemeId(created.id);
      setThemeMessage({ type: 'success', text: t('themes.created') });
    } catch (err) {
      if (isApiError(err)) {
        setThemeMessage({ type: 'error', text: err.message });
      } else {
        setThemeMessage({ type: 'error', text: t('common.error') });
      }
    } finally {
      setCreating(false);
    }
  };

  // ---- Save theme settings ----
  const handleSaveTheme = async () => {
    const themeId = selectedThemeId();
    if (!themeId) return;

    setSavingTheme(true);
    setThemeMessage(null);

    try {
      const data: UpdateThemeRequest = {
        name: editName(),
        theme: editThemeTopic(),
        categories: editCategories(),
        max_age_days: editMaxAge(),
        max_items_per_category: editMaxItems(),
        summary_length: editSummaryLength(),
      };
      const updated = await themesApi.update(themeId, data);
      setThemes((prev) => prev.map((th) => (th.id === themeId ? updated : th)));
      setThemeMessage({ type: 'success', text: t('themes.saved') });
    } catch (err) {
      if (isApiError(err)) {
        setThemeMessage({ type: 'error', text: err.message });
      } else {
        setThemeMessage({ type: 'error', text: t('common.error') });
      }
    } finally {
      setSavingTheme(false);
    }
  };

  // ---- Delete theme ----
  const handleDeleteThemeClick = () => {
    if (confirmingDeleteTheme()) {
      performDeleteTheme();
    } else {
      setConfirmingDeleteTheme(true);
      if (deleteThemeTimer) clearTimeout(deleteThemeTimer);
      deleteThemeTimer = setTimeout(() => {
        setConfirmingDeleteTheme(false);
      }, 5000);
    }
  };

  const performDeleteTheme = async () => {
    const themeId = selectedThemeId();
    if (!themeId) return;

    if (deleteThemeTimer) clearTimeout(deleteThemeTimer);
    setConfirmingDeleteTheme(false);

    try {
      await themesApi.remove(themeId);
      setThemes((prev) => prev.filter((th) => th.id !== themeId));
      setSelectedThemeId(null);
      setThemeMessage({ type: 'success', text: t('themes.deleted') });
    } catch (err) {
      if (isApiError(err)) {
        setThemeMessage({ type: 'error', text: err.message });
      } else {
        setThemeMessage({ type: 'error', text: t('common.error') });
      }
    }
  };

  // ---- Category management ----
  const handleAddCategory = () => {
    const cat = newCategory().trim();
    if (cat && !editCategories().includes(cat)) {
      setEditCategories((prev) => [...prev, cat]);
      setNewCategory('');
    }
  };

  const handleRemoveCategory = (cat: string) => {
    setEditCategories((prev) => prev.filter((c) => c !== cat));
  };

  // ---- Summary length helpers ----
  const summaryLengthLabel = (): string => {
    const val = editSummaryLength();
    if (val <= 1) return t('settings.summaryShort');
    if (val >= 3) return t('settings.summaryDetailed');
    return t('settings.summaryMedium');
  };

  // ---- Add a single source ----
  const handleAddSource = async (e: SubmitEvent) => {
    e.preventDefault();
    const themeId = selectedThemeId();
    if (!themeId) return;

    setAddError(null);

    const title = newTitle().trim();
    const rawUrl = newUrl().trim();

    if (!title) {
      setAddError(t('sources.titleRequired'));
      return;
    }
    if (!rawUrl) {
      setAddError(t('sources.urlRequired'));
      return;
    }

    const url = normalizeUrl(rawUrl);
    if (!isValidUrl(url)) {
      setAddError(t('sources.urlInvalid'));
      return;
    }

    setAdding(true);
    try {
      await sourcesApi.create({ title, url, theme_id: themeId });
      setNewTitle('');
      setNewUrl('');
      await fetchSources(themeId);
    } catch (err) {
      if (isApiError(err)) {
        setAddError(err.message);
      } else {
        setAddError(t('sources.addError'));
      }
    } finally {
      setAdding(false);
    }
  };

  // ---- Delete source with confirmation ----
  const handleDeleteClick = (id: string) => {
    if (confirmingDeleteId() === id) {
      performDelete(id);
    } else {
      setConfirmingDeleteId(id);
      if (deleteTimer) clearTimeout(deleteTimer);
      deleteTimer = setTimeout(() => {
        setConfirmingDeleteId(null);
      }, 3000);
    }
  };

  const performDelete = async (id: string) => {
    if (deleteTimer) clearTimeout(deleteTimer);
    setConfirmingDeleteId(null);

    const themeId = selectedThemeId();
    try {
      await sourcesApi.remove(id);
      if (themeId) await fetchSources(themeId);
    } catch (err) {
      console.error('Failed to delete source:', err);
    }
  };

  // ---- Toggle preferred source ----
  const handleTogglePreferred = async (sourceId: string) => {
    const themeId = selectedThemeId();
    if (!themeId) return;

    const current = sources();
    const toggled = current.map((s) =>
      s.id === sourceId ? { ...s, is_preferred: !s.is_preferred } : s,
    );
    const newPreferredIds = toggled.filter((s) => s.is_preferred).map((s) => s.id);

    // Optimistically update local state
    setSources(toggled);

    try {
      await sourcesApi.updatePreferred(newPreferredIds, themeId);
    } catch (err) {
      // Revert on error
      setSources(current);
      console.error('Failed to update preferred sources:', err);
    }
  };

  const preferredCount = (): number => sources().filter((s) => s.is_preferred).length;

  // ---- CSV Export ----
  const handleExportCsv = async () => {
    setCsvError(null);
    try {
      await sourcesApi.exportCsv(selectedThemeId() ?? undefined);
    } catch {
      setCsvError(t('sources.exportError'));
    }
  };

  // ---- CSV Import ----
  const handleImportCsv = async (e: Event) => {
    const input = e.target as HTMLInputElement;
    const file = input.files?.[0];
    if (!file) return;

    const themeId = selectedThemeId();
    if (!themeId) return;

    setImporting(true);
    setCsvError(null);

    try {
      await sourcesApi.importCsv(file, themeId);
      await fetchSources(themeId);
    } catch (err) {
      if (isApiError(err)) {
        setCsvError(err.message);
      } else {
        setCsvError(t('sources.csvImportError'));
      }
    } finally {
      setImporting(false);
      input.value = '';
    }
  };

  // ---- Bulk Import ----
  const handleBulkImport = async (e: SubmitEvent) => {
    e.preventDefault();
    if (!bulkText().trim()) return;

    const themeId = selectedThemeId();
    if (!themeId) return;

    setImporting(true);
    setImportError(null);

    const lines = bulkText()
      .split('\n')
      .map((l) => l.trim())
      .filter((l) => l.length > 0);

    const validSources: { title: string; url: string; theme_id?: string }[] = [];

    for (const line of lines) {
      const parts = line.split(';');
      if (parts.length >= 2) {
        const title = parts[0].trim();
        const url = normalizeUrl(parts.slice(1).join(';').trim());
        if (title && url) {
          validSources.push({ title, url, theme_id: themeId });
        }
      }
    }

    if (validSources.length === 0) {
      setImportError(t('sources.bulkImportError'));
      setImporting(false);
      return;
    }

    try {
      await sourcesApi.bulkImport({ sources: validSources, theme_id: themeId });
      setBulkText('');
      await fetchSources(themeId);
    } catch (err) {
      if (isApiError(err)) {
        setImportError(err.message);
      } else {
        setImportError(t('sources.bulkImportError'));
      }
    } finally {
      setImporting(false);
    }
  };

  // ---- Render ----
  return (
    <Show when={!loading()} fallback={<LoadingSpinner />}>
      <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        {/* Page header */}
        <div class="mb-8">
          <h1 class="text-3xl font-bold text-gray-900">
            {t('themes.title')}
          </h1>
        </div>

        {/* Message banner (persists above theme selector for create/delete feedback) */}
        <Show when={themeMessage()}>
          {(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>

        {/* Theme selector */}
        <div class="mb-8 flex items-center gap-4">
          <select
            class="block w-full pl-3 pr-10 py-2 text-sm border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 rounded-md border bg-white"
            value={selectedThemeId() ?? ''}
            onChange={(e) => {
              const val = e.currentTarget.value;
              setSelectedThemeId(val || null);
            }}
          >
            <option value="">{t('themes.selectTheme')}</option>
            <For each={themes()}>
              {(theme) => (
                <option value={theme.id}>{theme.name}</option>
              )}
            </For>
          </select>
          <Button
            onClick={handleCreateTheme}
            loading={creating()}
            icon={Plus}
          >
            {t('themes.createTheme')}
          </Button>
        </div>

        {/* No themes message */}
        <Show when={themes().length === 0 && !selectedThemeId()}>
          <div class="text-center py-12 text-gray-500">
            <p>{t('themes.noThemes')}</p>
          </div>
        </Show>

        {/* Selected theme content */}
        <Show when={selectedTheme()}>
          {(theme) => (
            <>
              {/* ── Content settings card ── */}
              <div class="mb-8 bg-white shadow-sm rounded-lg border border-gray-200 p-6">
                <h2 class="text-xl font-semibold text-gray-900 mb-4">
                  {t('themes.contentSection')}
                </h2>

                <div class="space-y-6">
                  {/* Theme name */}
                  <div>
                    <label
                      for="theme-name"
                      class="block text-sm font-medium text-gray-700"
                    >
                      {t('themes.name')}
                    </label>
                    <div class="mt-1">
                      <input
                        type="text"
                        id="theme-name"
                        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={editName()}
                        onInput={(e) => setEditName(e.currentTarget.value)}
                      />
                    </div>
                  </div>

                  {/* Search topic */}
                  <div>
                    <label
                      for="theme-topic"
                      class="block text-sm font-medium text-gray-700"
                    >
                      {t('themes.searchTopic')}
                    </label>
                    <p class="text-xs text-gray-500 mb-1">
                      {t('themes.searchTopicHelp')}
                    </p>
                    <div class="mt-1">
                      <input
                        type="text"
                        id="theme-topic"
                        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={editThemeTopic()}
                        onInput={(e) => setEditThemeTopic(e.currentTarget.value)}
                        placeholder={t('settings.themeHelp')}
                      />
                    </div>
                  </div>

                  {/* Categories */}
                  <div>
                    <label class="block text-sm font-medium text-gray-700 mb-2">
                      {t('settings.categories')}
                    </label>
                    <div class="flex flex-wrap gap-2 mb-3">
                      <For each={editCategories()}>
                        {(cat) => (
                          <span class="inline-flex items-center px-3 py-1 rounded-full text-sm bg-indigo-100 text-indigo-800">
                            {cat}
                            <button
                              type="button"
                              onClick={() => handleRemoveCategory(cat)}
                              class="ml-1.5 text-indigo-600 hover:text-indigo-900"
                              title={t('settings.removeCategory')}
                            >
                              &times;
                            </button>
                          </span>
                        )}
                      </For>
                    </div>
                    <div class="flex gap-2">
                      <input
                        type="text"
                        class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block flex-1 sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                        placeholder={t('settings.newCategory')}
                        value={newCategory()}
                        onInput={(e) => setNewCategory(e.currentTarget.value)}
                        onKeyDown={(e) => {
                          if (e.key === 'Enter') {
                            e.preventDefault();
                            handleAddCategory();
                          }
                        }}
                      />
                      <Button
                        type="button"
                        variant="secondary"
                        onClick={handleAddCategory}
                        icon={Plus}
                      >
                        {t('settings.addCategory')}
                      </Button>
                    </div>
                  </div>

                  {/* Max age + Max items */}
                  <div class="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-2">
                    <div>
                      <label
                        for="theme-max-age"
                        class="block text-sm font-medium text-gray-700"
                      >
                        {t('settings.maxAgeDays')}
                      </label>
                      <div class="mt-1">
                        <input
                          type="number"
                          id="theme-max-age"
                          min="1"
                          max="90"
                          class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-24 sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                          value={editMaxAge()}
                          onInput={(e) =>
                            setEditMaxAge(parseInt(e.currentTarget.value) || 7)
                          }
                        />
                      </div>
                    </div>
                    <div>
                      <label
                        for="theme-max-items"
                        class="block text-sm font-medium text-gray-700"
                      >
                        {t('settings.maxItems')}
                      </label>
                      <div class="mt-1">
                        <input
                          type="number"
                          id="theme-max-items"
                          min="1"
                          max="20"
                          class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-24 sm:text-sm border-gray-300 rounded-md py-2 px-3 border"
                          value={editMaxItems()}
                          onInput={(e) =>
                            setEditMaxItems(parseInt(e.currentTarget.value) || 5)
                          }
                        />
                      </div>
                    </div>
                  </div>

                  {/* Summary length slider */}
                  <div>
                    <label
                      for="theme-summary-length"
                      class="block text-sm font-medium text-gray-700"
                    >
                      {t('settings.summaryLength')}
                    </label>
                    <p class="text-xs text-gray-500 mb-2">
                      {t('settings.summaryLengthHelp')}
                    </p>
                    <div class="flex items-center gap-4">
                      <input
                        type="range"
                        id="theme-summary-length"
                        min="1"
                        max="3"
                        step="1"
                        class="w-48"
                        value={editSummaryLength()}
                        onInput={(e) =>
                          setEditSummaryLength(parseInt(e.currentTarget.value) || 2)
                        }
                      />
                      <span class="text-sm font-medium text-gray-700">
                        {summaryLengthLabel()}
                      </span>
                    </div>
                  </div>
                </div>

                {/* Save button */}
                <div class="mt-6 flex justify-end">
                  <Button
                    onClick={handleSaveTheme}
                    loading={savingTheme()}
                    icon={Save}
                  >
                    {t('common.save')}
                  </Button>
                </div>
              </div>

              {/* ── Sources card ── */}
              <div class="mb-8 bg-white shadow-sm rounded-lg border border-gray-200 p-6">
                <h2 class="text-xl font-semibold text-gray-900 mb-4">
                  {t('sources.title')}
                </h2>
                <p class="text-sm text-gray-500 mb-6">
                  {t('sources.subtitle')}
                </p>

                {/* Add a source */}
                <div class="mb-6">
                  <h3 class="text-base font-medium text-gray-900 mb-3">
                    {t('sources.addTitle')}
                  </h3>
                  <form
                    onSubmit={handleAddSource}
                    class="space-y-4 sm:flex sm:space-y-0 sm:space-x-4"
                  >
                    <div class="flex-1">
                      <label for="source-title" class="sr-only">
                        {t('sources.titleLabel')}
                      </label>
                      <input
                        type="text"
                        id="source-title"
                        class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border"
                        placeholder={t('sources.titlePlaceholder')}
                        value={newTitle()}
                        onInput={(e) => setNewTitle(e.currentTarget.value)}
                      />
                    </div>
                    <div class="flex-1">
                      <label for="source-url" class="sr-only">
                        {t('sources.urlLabel')}
                      </label>
                      <input
                        type="text"
                        id="source-url"
                        class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border"
                        placeholder={t('sources.urlPlaceholder')}
                        value={newUrl()}
                        onInput={(e) => setNewUrl(e.currentTarget.value)}
                      />
                    </div>
                    <Button
                      type="submit"
                      loading={adding()}
                      icon={Plus}
                    >
                      {t('sources.add')}
                    </Button>
                  </form>
                  <Show when={addError()}>
                    {(msg) => (
                      <p class="mt-2 text-sm text-red-600">{msg()}</p>
                    )}
                  </Show>
                </div>

                {/* CSV Import / Export */}
                <div class="mb-6">
                  <h3 class="text-base font-medium text-gray-900 mb-3">
                    {t('sources.csvSection')}
                  </h3>
                  <p class="text-sm text-gray-500 mb-3">
                    {t('sources.csvDescription')}
                  </p>
                  <div class="flex space-x-4">
                    <button
                      onClick={handleExportCsv}
                      class="inline-flex items-center px-4 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"
                    >
                      <Download class="h-4 w-4 mr-2" />
                      {t('sources.exportCsv')}
                    </button>
                    <label class="inline-flex items-center px-4 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 cursor-pointer">
                      <Upload class="h-4 w-4 mr-2" />
                      {t('sources.importCsv')}
                      <input
                        ref={fileInputRef}
                        type="file"
                        class="hidden"
                        accept=".csv"
                        onChange={handleImportCsv}
                        disabled={importing()}
                      />
                    </label>
                  </div>
                  <Show when={csvError()}>
                    {(msg) => (
                      <p class="mt-2 text-sm text-red-600">{msg()}</p>
                    )}
                  </Show>
                </div>

                {/* Bulk Import */}
                <div class="mb-6">
                  <h3 class="text-base font-medium text-gray-900 mb-3">
                    {t('sources.bulkSection')}
                  </h3>
                  <p class="text-sm text-gray-500 mb-3">
                    {t('sources.bulkDescription')}{' '}
                    <strong>{t('sources.bulkFormat')}</strong>
                  </p>
                  <form onSubmit={handleBulkImport} class="space-y-4">
                    <div>
                      <label for="bulk-import" class="sr-only">
                        {t('sources.bulkSection')}
                      </label>
                      <textarea
                        id="bulk-import"
                        rows={5}
                        class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border"
                        placeholder={t('sources.bulkPlaceholder')}
                        value={bulkText()}
                        onInput={(e) => setBulkText(e.currentTarget.value)}
                      />
                    </div>
                    <Show when={importError()}>
                      {(msg) => (
                        <p class="text-sm text-red-600">{msg()}</p>
                      )}
                    </Show>
                    <button
                      type="submit"
                      disabled={importing() || !bulkText().trim()}
                      class="inline-flex items-center justify-center px-4 py-2 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"
                    >
                      {importing()
                        ? t('sources.importing')
                        : t('sources.bulkImport')}
                    </button>
                  </form>
                </div>

                {/* Source list */}
                <Show when={loadingSources()}>
                  <LoadingSpinner />
                </Show>
                <Show when={!loadingSources()}>
                  <div class="bg-white shadow overflow-hidden sm:rounded-md">
                    <ul class="divide-y divide-gray-200">
                      <Show
                        when={sources().length > 0}
                        fallback={
                          <li class="px-4 py-8 text-center text-gray-500">
                            <p>{t('sources.empty')}</p>
                            <p class="mt-1 text-xs">{t('sources.emptyHint')}</p>
                          </li>
                        }
                      >
                        <For each={sources()}>
                          {(source) => (
                            <li>
                              <div class={`px-4 py-4 flex items-center sm:px-6 ${source.is_preferred ? 'bg-amber-50' : ''}`}>
                                <div class="flex-shrink-0 mr-3">
                                  <button
                                    type="button"
                                    onClick={() => handleTogglePreferred(source.id)}
                                    class={`p-1 rounded transition-colors ${
                                      source.is_preferred
                                        ? 'text-amber-500 hover:text-amber-600'
                                        : 'text-gray-300 hover:text-amber-400'
                                    }`}
                                    title={t('sources.preferred')}
                                  >
                                    <Star class={`h-5 w-5 ${source.is_preferred ? 'fill-current' : ''}`} />
                                  </button>
                                </div>
                                <div class="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
                                  <div class="truncate">
                                    <div class="flex text-sm">
                                      <p class="font-medium text-indigo-600 truncate">
                                        {source.title}
                                      </p>
                                    </div>
                                    <div class="mt-2 flex">
                                      <div class="flex items-center text-sm text-gray-500">
                                        <LinkIcon class="flex-shrink-0 mr-1.5 h-4 w-4 text-gray-400" />
                                        <a
                                          href={source.url}
                                          target="_blank"
                                          rel="noopener noreferrer"
                                          class="truncate hover:underline"
                                        >
                                          {source.url}
                                        </a>
                                      </div>
                                    </div>
                                  </div>
                                </div>
                                <div class="ml-5 flex-shrink-0">
                                  <button
                                    onClick={() => handleDeleteClick(source.id)}
                                    class={`p-2 transition-colors ${
                                      confirmingDeleteId() === source.id
                                        ? 'text-red-600 bg-red-50 rounded-md'
                                        : 'text-gray-400 hover:text-red-600'
                                    }`}
                                    title={
                                      confirmingDeleteId() === source.id
                                        ? t('sources.confirmDelete')
                                        : t('sources.deleteTitle')
                                    }
                                  >
                                    <Show
                                      when={confirmingDeleteId() === source.id}
                                      fallback={<Trash2 class="h-5 w-5" />}
                                    >
                                      <span class="text-xs font-medium">
                                        {t('sources.confirmDelete')}
                                      </span>
                                    </Show>
                                  </button>
                                </div>
                              </div>
                            </li>
                          )}
                        </For>
                      </Show>
                    </ul>
                  </div>
                  <Show when={preferredCount() > 0}>
                    <div class="mt-3 flex items-center gap-2 text-sm text-amber-700">
                      <Star class="h-4 w-4 fill-current text-amber-500" />
                      <span>
                        {t('sources.preferredCount').replace('{count}', String(preferredCount()))}
                      </span>
                    </div>
                    <p class="mt-1 text-xs text-gray-500">
                      {t('sources.preferredHelp')}
                    </p>
                  </Show>
                </Show>
              </div>

              {/* ── Schedule card ── */}
              <SettingsSchedule themeId={selectedThemeId()!} />

              {/* ── Delete theme ── */}
              <div class="mt-8">
                <Button
                  variant="danger"
                  onClick={handleDeleteThemeClick}
                  icon={Trash2}
                >
                  {confirmingDeleteTheme()
                    ? t('themes.deleteConfirm')
                    : t('themes.deleteTheme')}
                </Button>
              </div>
            </>
          )}
        </Show>
      </div>
    </Show>
  );
};

export default ThemeManager;
