import {
  type Component,
  createSignal,
  createResource,
  Show,
  For,
} from 'solid-js';
import { Key, Eye, EyeOff, CheckCircle, XCircle, Trash2, RefreshCw } from 'lucide-solid';
import { apiKeysApi } from '~/api/apiKeys';
import { useI18n } from '~/i18n';
import { useToast } from '~/components/ui/Toast';
import { isApiError } from '~/types';
import type { ProviderConfig, UserApiKey } from '~/types';

interface ApiKeyManagerProps {
  providers: ProviderConfig[];
}

/**
 * Manages per-provider API keys (BYOK) displayed on the Settings page.
 *
 * Renders one {@link ProviderKeyCard} per configured provider. The card
 * supports creating, testing, and deleting keys, as well as toggling
 * key visibility (show/hide). The `test` button makes a live validation
 * call to verify the key works.
 */
const ApiKeyManager: Component<ApiKeyManagerProps> = (props) => {
  const { t } = useI18n();
  const { addToast } = useToast();

  const [apiKeys, { refetch }] = createResource(() => apiKeysApi.list());

  const getKeyForProvider = (providerName: string): UserApiKey | undefined => {
    return apiKeys()?.find((k) => k.provider_name === providerName);
  };

  return (
    <div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200 mt-8">
      <div class="px-4 py-5 sm:px-6 border-b border-gray-200">
        <div class="flex items-center">
          <Key class="h-5 w-5 text-indigo-600 mr-2" />
          <h2 class="text-lg font-medium text-gray-900">
            {t('settings.apiKeys.title')}
          </h2>
        </div>
        <p class="mt-1 text-sm text-gray-500">
          {t('settings.apiKeys.description')}
        </p>
      </div>

      <div class="divide-y divide-gray-200">
        <For each={props.providers}>
          {(provider) => (
            <ProviderKeyCard
              provider={provider}
              apiKey={getKeyForProvider(provider.provider_name)}
              onKeyChanged={refetch}
            />
          )}
        </For>
      </div>
    </div>
  );
};

interface ProviderKeyCardProps {
  provider: ProviderConfig;
  apiKey: UserApiKey | undefined;
  onKeyChanged: () => void;
}

/** Individual card for a single provider's API key with CRUD and test actions. */
const ProviderKeyCard: Component<ProviderKeyCardProps> = (props) => {
  const { t } = useI18n();
  const { addToast } = useToast();

  const [keyInput, setKeyInput] = createSignal('');
  const [showKey, setShowKey] = createSignal(false);
  const [editing, setEditing] = createSignal(false);
  const [saving, setSaving] = createSignal(false);
  const [testing, setTesting] = createSignal(false);
  const [confirmDelete, setConfirmDelete] = createSignal(false);

  const isConfigured = () => !!props.apiKey;
  const showInput = () => !isConfigured() || editing();

  const handleSave = async () => {
    const key = keyInput().trim();
    if (!key) return;

    setSaving(true);
    try {
      await apiKeysApi.create({
        provider_name: props.provider.provider_name,
        api_key: key,
      });
      addToast({
        type: 'success',
        message: t('settings.apiKeys.saved'),
        duration: 4000,
      });
      setKeyInput('');
      setShowKey(false);
      setEditing(false);
      props.onKeyChanged();
    } catch (err) {
      const message = isApiError(err) ? err.message : t('settings.apiKeys.saveError');
      addToast({ type: 'error', message, duration: 5000 });
    } finally {
      setSaving(false);
    }
  };

  const handleTest = async () => {
    setTesting(true);
    try {
      const result = await apiKeysApi.test(props.provider.provider_name);
      if (result.success) {
        addToast({
          type: 'success',
          message: t('settings.apiKeys.testSuccess'),
          duration: 4000,
        });
      } else {
        addToast({
          type: 'error',
          message: t('settings.apiKeys.testFailure', { message: result.message }),
          duration: 6000,
        });
      }
    } catch (err) {
      const message = isApiError(err) ? err.message : t('settings.apiKeys.testFailure', { message: 'Erreur inconnue' });
      addToast({ type: 'error', message, duration: 5000 });
    } finally {
      setTesting(false);
    }
  };

  const handleDelete = async () => {
    try {
      await apiKeysApi.remove(props.provider.provider_name);
      addToast({
        type: 'success',
        message: t('settings.apiKeys.deleted'),
        duration: 4000,
      });
      setConfirmDelete(false);
      setEditing(false);
      props.onKeyChanged();
    } catch (err) {
      const message = isApiError(err) ? err.message : t('settings.apiKeys.deleteError');
      addToast({ type: 'error', message, duration: 5000 });
    }
  };

  const handleCancel = () => {
    setEditing(false);
    setKeyInput('');
    setShowKey(false);
    setConfirmDelete(false);
  };

  return (
    <div class="px-4 py-4 sm:px-6">
      {/* Header: Provider name + status badge */}
      <div class="flex items-center justify-between mb-3">
        <div class="flex items-center gap-3">
          <span class="text-sm font-medium text-gray-900">
            {props.provider.display_name}
          </span>
          <Show
            when={isConfigured()}
            fallback={
              <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600">
                {t('settings.apiKeys.notConfigured')}
              </span>
            }
          >
            <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
              {t('settings.apiKeys.configured')}
            </span>
          </Show>
        </div>

        {/* Action buttons for configured keys */}
        <Show when={isConfigured() && !editing()}>
          <div class="flex items-center gap-2">
            <button
              type="button"
              onClick={handleTest}
              disabled={testing()}
              class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md text-indigo-700 bg-indigo-50 hover:bg-indigo-100 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-indigo-500 disabled:opacity-50"
            >
              <Show
                when={!testing()}
                fallback={
                  <div class="animate-spin rounded-full h-3 w-3 border-b-2 border-indigo-700 mr-1.5" />
                }
              >
                <RefreshCw class="h-3 w-3 mr-1.5" />
              </Show>
              {testing() ? t('settings.apiKeys.testing') : t('settings.apiKeys.test')}
            </button>
            <button
              type="button"
              onClick={() => setEditing(true)}
              class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md text-gray-700 bg-gray-100 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-indigo-500"
            >
              {t('settings.apiKeys.update')}
            </button>
            <Show
              when={!confirmDelete()}
              fallback={
                <div class="flex items-center gap-1">
                  <button
                    type="button"
                    onClick={handleDelete}
                    class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-red-500"
                  >
                    {t('common.confirm')}
                  </button>
                  <button
                    type="button"
                    onClick={() => setConfirmDelete(false)}
                    class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md text-gray-700 bg-gray-100 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-indigo-500"
                  >
                    {t('common.cancel')}
                  </button>
                </div>
              }
            >
              <button
                type="button"
                onClick={() => setConfirmDelete(true)}
                class="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-md text-red-700 bg-red-50 hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-red-500"
              >
                <Trash2 class="h-3 w-3 mr-1.5" />
                {t('settings.apiKeys.delete')}
              </button>
            </Show>
          </div>
        </Show>
      </div>

      {/* Key prefix display */}
      <Show when={isConfigured() && !editing()}>
        <p class="text-sm text-gray-500">
          <span class="font-mono text-gray-400">
            {t('settings.apiKeys.keyPrefix', { prefix: props.apiKey!.key_prefix })}
          </span>
        </p>
      </Show>

      {/* Input form: shown when not configured or editing */}
      <Show when={showInput()}>
        <div class="mt-2">
          <label
            for={`api-key-${props.provider.provider_name}`}
            class="block text-sm font-medium text-gray-700 mb-1"
          >
            {t('settings.apiKeys.inputLabel')}
          </label>
          <div class="flex items-center gap-2">
            <div class="relative flex-1">
              <input
                type={showKey() ? 'text' : 'password'}
                id={`api-key-${props.provider.provider_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 pr-10 border font-mono"
                value={keyInput()}
                onInput={(e) => setKeyInput(e.currentTarget.value)}
                placeholder={t('settings.apiKeys.inputPlaceholder', {
                  provider: props.provider.display_name,
                })}
              />
              <button
                type="button"
                onClick={() => setShowKey(!showKey())}
                class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600"
                aria-label={showKey() ? t('settings.apiKeys.hideKey') : t('settings.apiKeys.showKey')}
              >
                <Show when={showKey()} fallback={<Eye class="h-4 w-4" />}>
                  <EyeOff class="h-4 w-4" />
                </Show>
              </button>
            </div>
            <button
              type="button"
              onClick={handleSave}
              disabled={saving() || !keyInput().trim()}
              class="inline-flex items-center px-4 py-2 border border-transparent 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()}>
                <div class="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
              </Show>
              {saving() ? t('settings.apiKeys.saving') : t('settings.apiKeys.save')}
            </button>
            <Show when={editing()}>
              <button
                type="button"
                onClick={handleCancel}
                class="inline-flex items-center px-4 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-indigo-500"
              >
                {t('common.cancel')}
              </button>
            </Show>
          </div>
        </div>
      </Show>
    </div>
  );
};

export default ApiKeyManager;
