<!-- #region Settings.ConnectionsTab [C:2] [TYPE Component] [SEMANTICS settings,connections,ui] -->
<!-- @ingroup Settings -->
<!-- @BRIEF Settings tab for managing database connections: list, add/edit form, test, delete with dependency check. -->
<!-- @UX_STATE idle, loading, empty, populated, adding, editing, testing, test_success, test_error, deleting, delete_blocked -->
<!-- @UX_FEEDBACK spinner during test; toast on save/delete; dialect badge colors; masked password with reveal toggle; test result inline -->
<!-- @UX_RECOVERY test_error -> edit and retry test; delete_blocked -> 'Show affected jobs' link in warning modal -->
<!-- @UX_TEST idle -> {click: "Add Connection"} -> adding -> fill form -> {click: "Test"} -> testing -> test_success -> {click: "Save"} -> populated -->
<script lang="ts">
  import { getT } from "$lib/i18n/index.svelte.js";
  import { Button, EmptyState, ConfirmDialog } from "$lib/ui";
  import { api } from "$lib/api.js";
  import { addToast } from "$lib/toasts.svelte.js";
  import { log } from "$lib/cot-logger";

  const _t = $derived(getT());

  interface Connection {
    id: string;
    name: string;
    host: string;
    port: number;
    database: string;
    username: string;
    password: string;
    dialect: string;
    extra_params: Record<string, unknown>;
    pool_size: number;
    created_at: string;
    updated_at: string;
    used_by?: number;
  }

  type ScreenState = "idle" | "loading" | "empty" | "populated" | "adding" | "editing" | "testing" | "test_success" | "test_error" | "deleting" | "delete_blocked";

  let connections = $state<Connection[]>([]);
  let screenState = $state<ScreenState>("loading");
  let showForm = $state(false);
  let editingId = $state<string | null>(null);
  let testResult = $state<{ success: boolean; latency_ms?: number; db_version?: string; error?: string } | null>(null);
  let blockDeleteJobs = $state<string[]>([]);
  let showDeleteConfirm = $state(false);
  let deleteTargetId: string | null = $state(null);

  // Form state
  let form = $state({
    name: "",
    host: "",
    port: 5432,
    database: "",
    username: "",
    password: "",
    dialect: "postgresql",
    extra_params: "",
    pool_size: 5,
  });

  const DIALECT_OPTIONS = [
    { value: "postgresql", label: "PostgreSQL", color: "bg-blue-100 text-blue-800" },
    { value: "clickhouse", label: "ClickHouse", color: "bg-orange-100 text-orange-800" },
    { value: "mysql", label: "MySQL", color: "bg-teal-100 text-teal-800" },
  ];

  function getDialectBadge(dialect: string): string {
    const opt = DIALECT_OPTIONS.find(d => d.value === dialect);
    return opt?.color ?? "bg-gray-100 text-gray-800";
  }

  async function loadConnections() {
    screenState = "loading";
    try {
      const data = await api.fetchConnections<Connection[]>();
      connections = data as Connection[];
      screenState = connections.length === 0 ? "empty" : "populated";
    } catch (err) {
      log("ConnectionsTab", "EXPLORE", "Failed to load connections", {}, String(err));
      addToast(_t.settings?.connections_load_failed ?? "Failed to load connections", "error");
      screenState = "empty";
    }
  }

  function openAddForm() {
    editingId = null;
    showForm = true;
    form = { name: "", host: "", port: 5432, database: "", username: "", password: "", dialect: "postgresql", extra_params: "", pool_size: 5 };
    testResult = null;
    screenState = "adding";
  }

  function openEditForm(conn: Connection) {
    editingId = conn.id;
    showForm = true;
    form = {
      name: conn.name,
      host: conn.host,
      port: conn.port,
      database: conn.database,
      username: conn.username,
      password: "",
      dialect: conn.dialect,
      extra_params: JSON.stringify(conn.extra_params ?? {}, null, 2),
      pool_size: conn.pool_size,
    };
    testResult = null;
    screenState = "editing";
  }

  function cancelForm() {
    showForm = false;
    editingId = null;
    screenState = connections.length === 0 ? "empty" : "populated";
  }

  function validateForm(): string | null {
    if (!form.name.trim()) return "Name is required";
    if (!form.host.trim()) return "Host is required";
    if (!form.database.trim()) return "Database is required";
    if (!form.username.trim()) return "Username is required";
    if (!editingId && !form.password) return "Password is required";
    if (form.port < 1 || form.port > 65535) return "Port must be between 1 and 65535";
    if (form.pool_size < 1 || form.pool_size > 100) return "Pool size must be 1-100";
    if (form.extra_params.trim()) {
      try {
        JSON.parse(form.extra_params);
      } catch {
        return "Extra params must be valid JSON";
      }
    }
    return null;
  }

  async function handleSave() {
    const validationError = validateForm();
    if (validationError) {
      addToast(validationError, "error");
      return;
    }

    try {
      const payload: Record<string, unknown> = {
        name: form.name.trim(),
        host: form.host.trim(),
        port: form.port,
        database: form.database.trim(),
        username: form.username.trim(),
        password: form.password,
        dialect: form.dialect,
        pool_size: form.pool_size,
      };
      if (form.extra_params.trim()) {
        payload.extra_params = JSON.parse(form.extra_params);
      }

      if (editingId) {
        await api.updateConnection(editingId, payload);
        addToast(_t.settings?.connections_updated ?? "Connection updated", "success");
      } else {
        await api.createConnection(payload);
        addToast(_t.settings?.connections_created ?? "Connection created", "success");
      }
      showForm = false;
      editingId = null;
      await loadConnections();
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : _t.settings?.connections_save_failed ?? "Save failed";
      addToast(msg, "error");
    }
  }

  async function handleTest() {
    screenState = "testing";
    testResult = null;
    try {
      const id = editingId ?? "__unsaved";
      let result: { success: boolean; latency_ms?: number; db_version?: string; error?: string };
      if (editingId) {
        result = await api.testConnection<{ success: boolean; latency_ms?: number; db_version?: string; error?: string }>(editingId);
      } else {
        // For unsaved connections, test via create with temporary save
        result = { success: false, error: "Save the connection first to test it" };
      }
      testResult = result;
      screenState = result.success ? "test_success" : "test_error";
      if (result.success) {
        addToast(`✅ Connected — ${result.latency_ms}ms`, "success");
      } else {
        addToast(`❌ ${result.error}`, "error");
      }
    } catch (err: unknown) {
      testResult = { success: false, error: err instanceof Error ? err.message : "Test failed" };
      screenState = "test_error";
      addToast("Test failed", "error");
    }
  }

  async function handleDelete(id: string) {
    screenState = "deleting";
    try {
      const result = await api.deleteConnection(id);
      addToast("Connection deleted", "success");
      await loadConnections();
    } catch (err: unknown) {
      // Check for 409 blocking error
      if (err && typeof err === "object" && "detail" in err) {
        const detail = (err as { detail: { blocking_jobs?: string[] } }).detail;
        blockDeleteJobs = detail?.blocking_jobs ?? [];
        screenState = "delete_blocked";
        addToast("Cannot delete — connection is in use", "warning");
      } else {
        addToast(err instanceof Error ? err.message : "Delete failed", "error");
        screenState = connections.length === 0 ? "empty" : "populated";
      }
    }
  }

  function confirmDelete(id: string) {
    deleteTargetId = id;
    showDeleteConfirm = true;
  }

  async function onConfirmDelete(): Promise<void> {
    if (deleteTargetId) {
      await handleDelete(deleteTargetId);
      deleteTargetId = null;
    }
  }

  // Load on mount
  $effect(() => {
    loadConnections();
  });
</script>

<div class="space-y-4">
  <div class="flex items-center justify-between">
    <h3 class="text-lg font-semibold text-text">{_t.settings?.connections_title || 'Database Connections'}</h3>
    <Button variant="primary" size="sm" onclick={openAddForm} disabled={screenState === "adding" || screenState === "editing"}>
      {_t.settings?.connections_add || '+ Add Connection'}
    </Button>
  </div>

  {#if screenState === "loading"}
    <div class="animate-pulse space-y-3">
      {#each [1, 2, 3] as _}
        <div class="h-16 bg-surface-muted rounded-lg"></div>
      {/each}
    </div>

  {:else if screenState === "empty" && !showForm}
    <EmptyState
      title={_t.settings?.connections_empty || 'No database connections configured.'}
      description={_t.settings?.connections_empty_hint || 'Add a connection to enable direct database inserts for translation jobs.'}
      actionLabel={_t.settings?.connections_add || '+ Add Connection'}
      onAction={openAddForm}
    />

  {:else if screenState === "populated" && !showForm}
    <div class="overflow-x-auto">
      <table class="min-w-full divide-y divide-border">
        <thead class="bg-surface-muted">
          <tr>
            <th class="px-3 py-2 text-left text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_name || 'Name'}</th>
            <th class="px-3 py-2 text-left text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_host || 'Host:Port'}</th>
            <th class="px-3 py-2 text-left text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_database || 'Database'}</th>
            <th class="px-3 py-2 text-left text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_dialect || 'Dialect'}</th>
            <th class="px-3 py-2 text-left text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_used_by || 'Used By'}</th>
            <th class="px-3 py-2 text-right text-xs font-medium text-text-muted uppercase tracking-wider">{_t.settings?.connections_actions || 'Actions'}</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-border">
          {#each connections as conn (conn.id)}
            <tr class="hover:bg-surface-muted/50">
              <td class="px-3 py-2 text-sm font-medium text-text">{conn.name}</td>
              <td class="px-3 py-2 text-sm text-text-muted">{conn.host}:{conn.port}</td>
              <td class="px-3 py-2 text-sm text-text-muted">{conn.database}</td>
              <td class="px-3 py-2 text-sm">
                <span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium {getDialectBadge(conn.dialect)}">
                  {conn.dialect}
                </span>
              </td>
              <td class="px-3 py-2 text-sm text-text-muted">{conn.used_by ?? 0} {_t.settings?.connections_used_by?.toLowerCase() || 'jobs'}</td>
              <td class="px-3 py-2 text-sm text-right space-x-2">
                <Button variant="ghost" size="sm" class="text-xs text-primary hover:underline" onclick={() => openEditForm(conn)}>{_t.settings?.connections_edit || 'Edit'}</Button>
                <Button variant="ghost" size="sm" class="text-xs text-primary hover:underline" onclick={async () => {
                  const r = await api.testConnection(conn.id);
                  if (r.success) addToast(`✅ ${_t.settings?.connections_test_success?.replace('{latency}', r.latency_ms) || `Connected — ${r.latency_ms}ms`}`, "success");
                  else addToast(`❌ ${_t.settings?.connections_test_failed || 'Test failed'}: ${r.error}`, "error");
                }}>{_t.settings?.connections_test || 'Test'}</Button>
                <Button variant="ghost" size="sm" class="text-xs text-destructive hover:underline" onclick={() => confirmDelete(conn.id)}>{_t.settings?.connections_delete || 'Delete'}</Button>
              </td>
            </tr>
          {/each}
        </tbody>
      </table>
    </div>
  {/if}

  {#if screenState === "delete_blocked"}
    <div class="p-4 border border-destructive-ring bg-destructive-light rounded-lg">
      <p class="text-sm font-medium text-destructive">{_t.settings?.connections_delete_blocked_title || 'Cannot delete connection'}</p>
      <p class="text-sm text-destructive mt-1">{_t.settings?.connections_delete_blocked_hint?.replace('{count}', blockDeleteJobs.length) || `This connection is used by ${blockDeleteJobs.length} active job(s):`}</p>
      {#if blockDeleteJobs.length > 0}
        <ul class="list-disc list-inside mt-1 text-sm text-destructive">
          {#each blockDeleteJobs as jobName}
            <li>{jobName}</li>
          {/each}
        </ul>
      {/if}
      <p class="text-sm text-destructive mt-1">{_t.settings?.connections_delete_blocked_help || 'Detach or reassign these jobs before deleting.'}</p>
      <Button variant="ghost" size="sm" class="text-sm text-primary hover:underline" onclick={() => { screenState = "populated"; blockDeleteJobs = []; }}>
        {_t.settings?.connections_dismiss || 'Dismiss'}
      </Button>
    </div>
  {/if}

  {#if showForm}
    <div class="border border-border rounded-lg p-4 space-y-3 bg-surface-card">
      <h4 class="text-base font-semibold text-text">{editingId ? (_t.settings?.connections_edit_title || 'Edit Connection') : (_t.settings?.connections_add_title || 'Add Connection')}</h4>

      <div class="grid grid-cols-2 gap-3">
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_name_label || 'Name *'}</label>
          <input class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.name} placeholder="My PostgreSQL" />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_dialect_label || 'Dialect *'}</label>
          <select class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.dialect}>
            {#each DIALECT_OPTIONS as opt}
              <option value={opt.value}>{opt.label}</option>
            {/each}
          </select>
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_host_label || 'Host *'}</label>
          <input class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.host} placeholder="db.internal.example.com" />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_port_label || 'Port *'}</label>
          <input type="number" class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.port} min="1" max="65535" />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_db_label || 'Database *'}</label>
          <input class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.database} placeholder="products_i18n" />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_user_label || 'Username *'}</label>
          <input class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.username} placeholder="translator" />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{editingId ? (_t.settings?.connections_password_keep || 'Password (leave empty to keep)') : (_t.settings?.connections_password_label || 'Password *')}</label>
          <input type="password" class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.password} placeholder={editingId ? "********" : "Enter password"} />
        </div>
        <div>
          <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_pool_label || 'Pool Size'}</label>
          <input type="number" class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card" bind:value={form.pool_size} min="1" max="100" />
        </div>
      </div>

      <div>
        <label class="block text-sm font-medium text-text-muted mb-1">{_t.settings?.connections_extra_label || 'Extra Params (JSON, optional)'}</label>
        <textarea class="w-full border border-border-strong rounded-md px-2 py-1.5 text-sm text-text bg-surface-card font-mono" bind:value={form.extra_params} rows={2} placeholder={JSON.stringify({"sslmode": "require"})}></textarea>
      </div>

      {#if testResult}
        <div class="text-sm p-2 rounded-md {testResult.success ? 'bg-success-light text-success' : 'bg-destructive-light text-destructive'}">
          {#if testResult.success}
            ✅ {_t.settings?.connections_test_success?.replace('{latency}', testResult.latency_ms) || `Connected — ${testResult.latency_ms}ms`} · {testResult.db_version}
          {:else}
            ❌ {testResult.error}
          {/if}
        </div>
      {/if}

      <div class="flex gap-2 pt-2">
        <Button variant="primary" size="sm" onclick={handleSave}>
          {editingId ? (_t.settings?.connections_update || 'Update Connection') : (_t.settings?.connections_save || 'Save Connection')}
        </Button>
        <Button variant="secondary" size="sm" onclick={handleTest} disabled={!editingId} title={!editingId ? (_t.settings?.connections_save_unsaved_test || 'Save the connection first to test it') : ''}>
          {_t.settings?.connections_test || 'Test Connection'}
        </Button>
        <Button variant="ghost" size="sm" onclick={cancelForm}>
          {_t.settings?.connections_cancel || 'Cancel'}
        </Button>
      </div>
    </div>
  {/if}
</div>

<ConfirmDialog
  bind:show={showDeleteConfirm}
  title="Delete connection?"
  message="Are you sure you want to delete this connection?"
  variant="destructive"
  confirmLabel="Delete"
  cancelLabel="Cancel"
  onConfirm={onConfirmDelete}
  onCancel={() => {}}
/>
<!-- #endregion Settings.ConnectionsTab -->
