<script lang="ts">
  import { onDestroy, onMount } from "svelte";
  import { Bot, Check, Eye, EyeOff, Globe, Key, LoaderCircle, X } from "@lucide/svelte";
  import { credDelete, credLoad, credSave } from "../git";
  import type { AiSettings, CommitAiProvider } from "../types";

  interface Props {
    settings: AiSettings;
    onSave: (settings: AiSettings) => void;
    onClose: () => void;
  }

  let { settings, onSave, onClose }: Props = $props();

  type CloudProvider = CommitAiProvider;

  const CRED_KEYS: Record<CloudProvider, string> = {
    openai: "ai:openai",
    anthropic: "ai:anthropic",
    custom: "ai:custom",
  };

  let provider = $state<CommitAiProvider>("openai");
  let openaiModel = $state("");
  let anthropicModel = $state("");
  let customBaseUrl = $state("");
  let customModel = $state("");

  let openaiApiKey = $state("");
  let anthropicApiKey = $state("");
  let customApiKey = $state("");
  let showKey = $state(false);
  let loadingKeys = $state(true);
  let saving = $state(false);
  let error = $state("");
  let errorHideTimer: ReturnType<typeof setTimeout> | undefined;

  $effect(() => {
    provider = settings.provider;
    openaiModel = settings.openaiModel;
    anthropicModel = settings.anthropicModel;
    customBaseUrl = settings.customBaseUrl;
    customModel = settings.customModel;
  });

  $effect(() => {
    if (errorHideTimer) clearTimeout(errorHideTimer);
    const currentError = error;
    if (currentError) {
      errorHideTimer = setTimeout(() => {
        if (error === currentError) error = "";
      }, 6000);
    }
  });

  onMount(() => {
    (async () => {
      try {
        const [openai, anthropic, custom] = await Promise.all([
          credLoad(CRED_KEYS.openai),
          credLoad(CRED_KEYS.anthropic),
          credLoad(CRED_KEYS.custom),
        ]);
        openaiApiKey = openai?.password ?? "";
        anthropicApiKey = anthropic?.password ?? "";
        customApiKey = custom?.password ?? "";
      } catch (err) {
        error = err instanceof Error ? err.message : String(err);
      } finally {
        loadingKeys = false;
      }
    })();
  });

  onDestroy(() => {
    if (errorHideTimer) clearTimeout(errorHideTimer);
  });

  async function persistKey(target: CloudProvider, value: string) {
    const key = CRED_KEYS[target];
    const trimmed = value.trim();
    if (trimmed) {
      await credSave(key, "api-key", trimmed);
    } else {
      await credDelete(key);
    }
  }

  async function handleSave() {
    saving = true;
    error = "";
    try {
      await Promise.all([
        persistKey("openai", openaiApiKey),
        persistKey("anthropic", anthropicApiKey),
        persistKey("custom", customApiKey),
      ]);
      onSave({
        provider,
        openaiModel: openaiModel.trim() || "gpt-4o-mini",
        anthropicModel: anthropicModel.trim() || "claude-3-5-haiku-latest",
        customBaseUrl: customBaseUrl.trim(),
        customModel: customModel.trim(),
      });
    } catch (err) {
      error = err instanceof Error ? err.message : String(err);
    } finally {
      saving = false;
    }
  }

</script>

<div
  class="dialog-backdrop"
  role="presentation"
>
  <div class="dialog ai-settings-dialog" role="dialog" aria-modal="true" aria-label="AI settings" tabindex="-1">
    <header class="dialog-header">
      <div>
        <span class="eyebrow">Commit AI</span>
        <h2 class="mt-0.5 text-ink text-base font-bold leading-tight">AI settings</h2>
      </div>
      <button class="dialog-close" type="button" onclick={onClose} title="Close">
        <X size={18} aria-hidden="true" />
      </button>
    </header>

    <form class="ai-settings-form" onsubmit={(e) => { e.preventDefault(); void handleSave(); }}>
      <div class="ai-provider-options" role="radiogroup" aria-label="AI provider">
        <button type="button" class="ai-provider-option" class:active={provider === "openai"} onclick={() => { provider = "openai"; }}>
          <Bot size={16} aria-hidden="true" />
          OpenAI
        </button>
        <button type="button" class="ai-provider-option" class:active={provider === "anthropic"} onclick={() => { provider = "anthropic"; }}>
          <Bot size={16} aria-hidden="true" />
          Anthropic (Claude)
        </button>
        <button type="button" class="ai-provider-option" class:active={provider === "custom"} onclick={() => { provider = "custom"; }}>
          <Globe size={16} aria-hidden="true" />
          Custom endpoint
        </button>
      </div>

      {#if provider === "openai"}
        <label class="cred-field">
          <span class="cred-field-label">Model</span>
          <input type="text" bind:value={openaiModel} placeholder="gpt-4o-mini" autocomplete="off" spellcheck="false" />
        </label>
        <div class="cred-field">
          <span class="cred-field-label">API key</span>
          <div class="cred-input">
            <Key size={15} class="cred-field-icon" aria-hidden="true" />
            <input
              type={showKey ? "text" : "password"}
              bind:value={openaiApiKey}
              placeholder="sk-..."
              autocomplete="off"
              spellcheck="false"
              disabled={loadingKeys}
            />
            <button type="button" class="cred-reveal" tabindex="-1" onclick={() => { showKey = !showKey; }} aria-label={showKey ? "Hide" : "Show"}>
              {#if showKey}<EyeOff size={14} aria-hidden="true" />{:else}<Eye size={14} aria-hidden="true" />{/if}
            </button>
          </div>
        </div>
      {:else if provider === "anthropic"}
        <label class="cred-field">
          <span class="cred-field-label">Model</span>
          <input type="text" bind:value={anthropicModel} placeholder="claude-3-5-haiku-latest" autocomplete="off" spellcheck="false" />
        </label>
        <div class="cred-field">
          <span class="cred-field-label">API key</span>
          <div class="cred-input">
            <Key size={15} class="cred-field-icon" aria-hidden="true" />
            <input
              type={showKey ? "text" : "password"}
              bind:value={anthropicApiKey}
              placeholder="sk-ant-..."
              autocomplete="off"
              spellcheck="false"
              disabled={loadingKeys}
            />
            <button type="button" class="cred-reveal" tabindex="-1" onclick={() => { showKey = !showKey; }} aria-label={showKey ? "Hide" : "Show"}>
              {#if showKey}<EyeOff size={14} aria-hidden="true" />{:else}<Eye size={14} aria-hidden="true" />{/if}
            </button>
          </div>
        </div>
      {:else}
        <label class="cred-field">
          <span class="cred-field-label">Endpoint URL</span>
          <input type="text" bind:value={customBaseUrl} placeholder="http://localhost:11434/v1" autocomplete="off" spellcheck="false" />
        </label>
        <label class="cred-field">
          <span class="cred-field-label">Model</span>
          <input type="text" bind:value={customModel} placeholder="llama3.1" autocomplete="off" spellcheck="false" />
        </label>
        <div class="cred-field">
          <span class="cred-field-label">API key (optional)</span>
          <div class="cred-input">
            <Key size={15} class="cred-field-icon" aria-hidden="true" />
            <input
              type={showKey ? "text" : "password"}
              bind:value={customApiKey}
              placeholder="Optional"
              autocomplete="off"
              spellcheck="false"
              disabled={loadingKeys}
            />
            <button type="button" class="cred-reveal" tabindex="-1" onclick={() => { showKey = !showKey; }} aria-label={showKey ? "Hide" : "Show"}>
              {#if showKey}<EyeOff size={14} aria-hidden="true" />{:else}<Eye size={14} aria-hidden="true" />{/if}
            </button>
          </div>
        </div>
        <div class="cred-token-hint">
          <Globe size={13} aria-hidden="true" />
          <span>For local OpenAI-compatible servers like Ollama or LM Studio. The base URL should end in /v1.</span>
        </div>
      {/if}

      {#if error}
        <p class="commit-block-reason">{error}</p>
      {/if}

      <div class="new-branch-actions">
        <button class="btn-secondary" type="button" onclick={onClose} disabled={saving}>
          Cancel
        </button>
        <button class="btn-primary" type="submit" disabled={saving || loadingKeys}>
          {#if saving}
            <LoaderCircle class="spin" size={16} aria-hidden="true" />
          {:else}
            <Check size={16} aria-hidden="true" />
          {/if}
          Save
        </button>
      </div>
    </form>
  </div>
</div>
