"use client";

export const dynamic = "force-dynamic";

import { useCallback, useEffect, useState } from "react";
import { Bot, KeyRound, Loader2, Plus, RefreshCw, Server, Trash2, X } from "lucide-react";

import { useAuth } from "@/auth/clerk";
import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { ProviderCredentialRead, ProviderUsageLiveRead } from "@/api/generated/model";
import { customFetch } from "@/api/mutator";
import {
  listProviderCredentialsApiV1ProviderCredentialsGet,
  createProviderCredentialApiV1ProviderCredentialsPost,
  updateProviderCredentialApiV1ProviderCredentialsCredentialIdPatch,
  deleteProviderCredentialApiV1ProviderCredentialsCredentialIdDelete,
  getProviderUsageLiveApiV1ProviderCredentialsCredentialIdUsageGet,
} from "@/api/generated/provider-credentials/provider-credentials";

// ---------------------------------------------------------------------------
// Provider metadata
// ---------------------------------------------------------------------------

const PROVIDERS = [
  {
    id: "anthropic",
    label: "Claude (Anthropic)",
    icon: Bot,
    description: "Anthropic Claude API key. Add multiple accounts to track separate keys or billing profiles.",
    keyLabel: "API Key",
    keyPlaceholder: "sk-ant-…",
    showBaseUrl: false,
    allowMultiple: true,
    accountKeyDefault: "default",
  },
  {
    id: "openai",
    label: "Codex / OpenAI",
    icon: Bot,
    description: "OpenAI API key. Add multiple accounts to track usage separately.",
    keyLabel: "API Key",
    keyPlaceholder: "sk-…",
    showBaseUrl: false,
    allowMultiple: true,
    accountKeyDefault: "",
  },
  {
    id: "ollama",
    label: "Ollama",
    icon: Server,
    description: "Ollama instance — local, on-prem, or cloud. Add the base URL; API key only needed for authenticated deployments.",
    keyLabel: "API Key (optional)",
    keyPlaceholder: "Leave blank for unauthenticated",
    showBaseUrl: true,
    allowMultiple: true,
    accountKeyDefault: "default",
  },
] as const;

type ProviderId = (typeof PROVIDERS)[number]["id"];

// ---------------------------------------------------------------------------
// Add/Edit form
// ---------------------------------------------------------------------------

interface CredentialFormProps {
  providerId: ProviderId;
  allowMultiple: boolean;
  showBaseUrl: boolean;
  keyLabel: string;
  keyPlaceholder: string;
  accountKeyDefault: string;
  onSave: (data: {
    account_key: string;
    display_name: string;
    api_key: string;
    base_url: string;
  }) => Promise<void>;
  onTest: (data: {
    account_key: string;
    api_key: string;
    base_url: string;
  }) => Promise<ProviderUsageLiveRead>;
  onCancel: () => void;
  isSaving: boolean;
  error: string | null;
}

function CredentialForm({
  allowMultiple,
  showBaseUrl,
  keyLabel,
  keyPlaceholder,
  accountKeyDefault,
  onSave,
  onTest,
  onCancel,
  isSaving,
  error,
}: CredentialFormProps) {
  const [accountKey, setAccountKey] = useState(accountKeyDefault);
  const [displayName, setDisplayName] = useState("");
  const [apiKey, setApiKey] = useState("");
  const [baseUrl, setBaseUrl] = useState("");
  const [isTesting, setIsTesting] = useState(false);
  const [testResult, setTestResult] = useState<ProviderUsageLiveRead | null>(null);
  const [testError, setTestError] = useState<string | null>(null);
  const canTest = showBaseUrl ? Boolean(baseUrl.trim()) : Boolean(apiKey.trim());

  const runTest = async () => {
    setIsTesting(true);
    setTestResult(null);
    setTestError(null);
    try {
      const result = await onTest({
        account_key: accountKey.trim() || accountKeyDefault || "test",
        api_key: apiKey.trim(),
        base_url: baseUrl.trim(),
      });
      setTestResult(result);
    } catch (err) {
      setTestError(err instanceof Error ? err.message : "Test failed.");
    } finally {
      setIsTesting(false);
    }
  };

  return (
    <div className="mt-3 rounded-xl border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-4">
      <div className="space-y-3">
        {allowMultiple && (
          <div>
            <label className="mb-1 block text-xs font-medium text-muted">
              Account name <span className="text-[color:var(--danger)]">*</span>
            </label>
            <Input
              value={accountKey}
              onChange={(e) => setAccountKey(e.target.value)}
              placeholder="e.g. work, personal, gpu-box"
              disabled={isSaving}
            />
            <p className="mt-1 text-[11px] text-muted">
              Used to tell accounts apart in cost reports.
            </p>
          </div>
        )}
        <div>
          <label className="mb-1 block text-xs font-medium text-muted">
            Display name (optional)
          </label>
          <Input
            value={displayName}
            onChange={(e) => setDisplayName(e.target.value)}
            placeholder={accountKey || "My account"}
            disabled={isSaving}
          />
        </div>
        {showBaseUrl && (
          <div>
            <label className="mb-1 block text-xs font-medium text-muted">
              Base URL <span className="text-[color:var(--danger)]">*</span>
            </label>
            <Input
              value={baseUrl}
              onChange={(e) => setBaseUrl(e.target.value)}
              placeholder="http://localhost:11434"
              disabled={isSaving}
            />
          </div>
        )}
        <div>
          <label className="mb-1 block text-xs font-medium text-muted">
            {keyLabel}
          </label>
          <Input
            type="password"
            value={apiKey}
            onChange={(e) => setApiKey(e.target.value)}
            placeholder={keyPlaceholder}
            disabled={isSaving}
            autoComplete="new-password"
          />
        </div>
        {error && (
          <p className="text-sm text-[color:var(--danger)]">{error}</p>
        )}
        <div className="flex gap-2">
          <Button
            variant="outline"
            size="sm"
            disabled={isSaving || isTesting || !canTest}
            onClick={runTest}
          >
            {isTesting ? (
              <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
            ) : (
              <RefreshCw className="mr-1.5 h-3.5 w-3.5" />
            )}
            {isTesting ? "Testing…" : "Test"}
          </Button>
          <Button
            size="sm"
            disabled={isSaving || !accountKey.trim() || (showBaseUrl && !baseUrl.trim())}
            onClick={() =>
              onSave({ account_key: accountKey.trim(), display_name: displayName.trim(), api_key: apiKey, base_url: baseUrl.trim() })
            }
          >
            {isSaving ? (
              <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
            ) : (
              <KeyRound className="mr-1.5 h-3.5 w-3.5" />
            )}
            {isSaving ? "Saving…" : "Save"}
          </Button>
          <Button variant="outline" size="sm" onClick={onCancel} disabled={isSaving}>
            <X className="mr-1.5 h-3.5 w-3.5" />
            Cancel
          </Button>
        </div>
        {testError && (
          <p className="text-sm text-[color:var(--danger)]">{testError}</p>
        )}
        {testResult && (
          <div className={`rounded-lg border p-3 text-xs ${
            testResult.reachable
              ? "border-[color:rgba(52,211,153,0.35)] bg-[color:rgba(52,211,153,0.08)]"
              : "border-[color:rgba(248,113,113,0.35)] bg-[color:rgba(248,113,113,0.08)]"
          }`}>
            <p className={`font-medium ${
              testResult.reachable ? "text-[color:var(--success)]" : "text-[color:var(--danger)]"
            }`}>
              {testResult.reachable ? "Connection successful" : "Connection failed"}
            </p>
            <p className="mt-1 text-muted">
              {testResult.error ?? (
                testResult.sample_input_tokens != null || testResult.sample_output_tokens != null
                  ? `Usage probe: in ${fmtTokens(testResult.sample_input_tokens)} · out ${fmtTokens(testResult.sample_output_tokens)}`
                  : "Connected."
              )}
            </p>
            {testResult.sample_latency_ms != null && (
              <p className="mt-1 text-muted">
                Probe time: {fmtLatencyMs(testResult.sample_latency_ms)}
              </p>
            )}

          </div>
        )}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Usage strip — live token data fetched from the provider
// ---------------------------------------------------------------------------

function fmtTokens(n: number | null | undefined): string {
  if (n == null) return "—";
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
  if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`;
  return n.toString();
}

function fmtResetMs(ms: number | null | undefined): string {
  if (ms == null || ms <= 0) return "now";
  const s = Math.floor(ms / 1000);
  if (s < 60) return `${s}s`;
  const m = Math.floor(s / 60);
  if (m < 60) return `${m}m ${s % 60}s`;
  const h = Math.floor(m / 60);
  return `${h}h ${m % 60}m`;
}

function fmtLatencyMs(ms: number | null | undefined): string {
  if (ms == null || ms < 0) return "—";
  if (ms < 1000) return `${ms}ms`;
  return `${(ms / 1000).toFixed(2)}s`;
}

function usageBarColor(pct: number): string {
  if (pct > 90) return "bg-[color:var(--danger)]";
  if (pct > 75) return "bg-[color:var(--warning)]";
  return "bg-[color:var(--success)]";
}

function fmtPct(pct: number): string {
  return `${Math.max(0, Math.min(100, pct)).toFixed(0)}%`;
}

interface UsageWindowBarProps {
  label: string;
  pct: number;
  resetInMs?: number | null;
}

function UsageWindowBar({ label, pct, resetInMs }: UsageWindowBarProps) {
  const clamped = Math.max(0, Math.min(100, pct));
  return (
    <div className="space-y-1">
      <div className="flex items-center justify-between text-[11px]">
        <span className="font-medium text-muted">{label}</span>
        <span className="tabular-nums text-strong">{fmtPct(clamped)} used</span>
      </div>
      <div className="h-1.5 overflow-hidden rounded-full bg-[color:var(--surface-strong)]">
        <div
          className={`h-full rounded-full transition-all ${usageBarColor(clamped)}`}
          style={{ width: `${clamped}%` }}
        />
      </div>
      <p className="text-[11px] text-muted">Resets in {fmtResetMs(resetInMs)}</p>
    </div>
  );
}

function UsageStrip({ credentialId, provider }: { credentialId: string; provider: string }) {
  const [usage, setUsage] = useState<ProviderUsageLiveRead | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [lastFetched, setLastFetched] = useState<Date | null>(null);

  const fetch = useCallback(async (refresh = false) => {
    setLoading(true);
    setError(null);
    try {
      const res = await getProviderUsageLiveApiV1ProviderCredentialsCredentialIdUsageGet(
        credentialId,
        refresh ? { refresh: true } : undefined,
      );
      if (res.status === 200) {
        setUsage(res.data);
        setLastFetched(new Date());
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to fetch usage.");
    } finally {
      setLoading(false);
    }
  }, [credentialId]);

  useEffect(() => { void fetch(); }, [fetch]);

  if (loading && !usage) {
    return (
      <div className="mt-2 flex items-center gap-2 text-xs text-muted">
        <Loader2 className="h-3 w-3 animate-spin" />
        Fetching live usage…
      </div>
    );
  }

  if (!usage?.reachable) {
    return (
      <div className="mt-2 flex items-center gap-2 text-xs text-[color:var(--danger)]">
        <span>{usage?.error ?? error ?? "Provider unreachable."}</span>
        <button type="button" onClick={() => fetch(true)} className="ml-1 underline hover:opacity-70">
          Retry
        </button>
      </div>
    );
  }

  const tok = usage.tokens;
  const inputTok = usage.input_tokens;
  const req = usage.requests;
  const isOllama = provider === "ollama";
  const sourceLabel: Record<string, string> = {
    provider_native: "Provider native",
    provider_api_rate_limit: "API rate limit",
    local_jsonl_estimate: "Local estimate",
    configured_limit: "Configured limit",
  };
  const usageBars: UsageWindowBarProps[] = [];
  if (inputTok.pct_used != null) {
    usageBars.push({
      label: "API rate limit · input tokens",
      pct: inputTok.pct_used,
      resetInMs: inputTok.reset_in_ms,
    });
  }
  if (tok.pct_used != null) {
    usageBars.push({
      label: "API rate limit · tokens",
      pct: tok.pct_used,
      resetInMs: tok.reset_in_ms,
    });
  }
  if (usageBars.length === 0 && req.limit != null && req.remaining != null && req.limit > 0) {
    usageBars.push({
      label: "API rate limit · requests",
      pct: ((req.limit - req.remaining) / req.limit) * 100,
      resetInMs: req.reset_in_ms,
    });
  }

  return (
    <div className="mt-2 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface)] p-2.5">
      {isOllama ? (
        <div className="space-y-1.5">
          <div className="text-[11px] text-muted">
            Source: {sourceLabel[usage.source] ?? usage.source} · confidence: {usage.confidence}
          </div>
          <div className="flex items-center gap-3 text-xs text-muted">
            <span className="flex items-center gap-1 text-[color:var(--success)]">
              <span className="inline-block h-1.5 w-1.5 rounded-full bg-[color:var(--success)]" />
              Connected
            </span>
            {(usage.models?.length ?? 0) > 0 && (
              <span>{usage.models!.length} model{usage.models!.length !== 1 ? "s" : ""} available</span>
            )}
            <button type="button" onClick={() => fetch(true)} className="ml-auto text-muted hover:text-strong">
              <RefreshCw className={`h-3 w-3 ${loading ? "animate-spin" : ""}`} />
            </button>
          </div>
          {usageBars.length > 0 ? (
            <div className="space-y-2">
              {usageBars.map((bar) => (
                <UsageWindowBar key={bar.label} label={bar.label} pct={bar.pct} resetInMs={bar.resetInMs} />
              ))}
            </div>
          ) : (
            <>
              {(usage.sample_input_tokens != null || usage.sample_output_tokens != null) && (
                <div className="flex items-center justify-between text-[11px] text-muted">
                  <span>Usage (last probe)</span>
                  <span className="tabular-nums text-strong">
                    in {fmtTokens(usage.sample_input_tokens)} · out {fmtTokens(usage.sample_output_tokens)}
                  </span>
                </div>
              )}
              {usage.sample_latency_ms != null && (
                <div className="flex items-center justify-between text-[11px] text-muted">
                  <span>Time (last probe)</span>
                  <span className="tabular-nums text-strong">
                    {fmtLatencyMs(usage.sample_latency_ms)}
                  </span>
                </div>
              )}
              <p className="text-[11px] text-muted">
                Provider did not return API rate-limit windows for percent + reset diagnostics.
              </p>
            </>
          )}
          <div className="flex items-center justify-between text-[11px] text-muted">
            {lastFetched && <span>Updated {Math.round((Date.now() - lastFetched.getTime()) / 1000)}s ago</span>}
          </div>
        </div>
      ) : (
        <div className="space-y-1.5">
          <div className="text-[11px] text-muted">
            Source: {sourceLabel[usage.source] ?? usage.source} · confidence: {usage.confidence}
          </div>
          {usageBars.length > 0 ? (
            <div className="space-y-2">
              {usageBars.map((bar) => (
                <UsageWindowBar key={bar.label} label={bar.label} pct={bar.pct} resetInMs={bar.resetInMs} />
              ))}
            </div>
          ) : (
            <>
              {(usage.sample_input_tokens != null || usage.sample_output_tokens != null) && (
                <div className="flex items-center justify-between text-[11px] text-muted">
                  <span>Usage (last probe)</span>
                  <span className="tabular-nums text-strong">
                    in {fmtTokens(usage.sample_input_tokens)} · out {fmtTokens(usage.sample_output_tokens)}
                  </span>
                </div>
              )}
              {usage.sample_latency_ms != null && (
                <div className="flex items-center justify-between text-[11px] text-muted">
                  <span>Time (last probe)</span>
                  <span className="tabular-nums text-strong">
                    {fmtLatencyMs(usage.sample_latency_ms)}
                  </span>
                </div>
              )}
              <p className="text-[11px] text-muted">
                Connected — provider did not return API rate-limit windows for percent + reset diagnostics.
              </p>
            </>
          )}

          <div className="flex items-center justify-between text-[11px] text-muted">
            {lastFetched && <span>Updated {Math.round((Date.now() - lastFetched.getTime()) / 1000)}s ago</span>}
            <button type="button" onClick={() => fetch(true)} className="ml-auto flex items-center gap-1 hover:text-strong">
              <RefreshCw className={`h-3 w-3 ${loading ? "animate-spin" : ""}`} />
              Refresh
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Credential row
// ---------------------------------------------------------------------------

interface CredentialRowProps {
  cred: ProviderCredentialRead;
  isAdmin: boolean;
  onDelete: (cred: ProviderCredentialRead) => void;
  onToggle: (cred: ProviderCredentialRead) => Promise<void>;
  showUsage?: boolean;
}

function CredentialRow({ cred, isAdmin, onDelete, onToggle, showUsage = true }: CredentialRowProps) {
  const [toggling, setToggling] = useState(false);
  return (
    <div
      className={`rounded-lg border px-3 py-2.5 ${
        cred.active
          ? "border-[color:var(--border)] bg-[color:var(--surface-muted)]"
          : "border-[color:var(--border)] bg-[color:var(--surface)] opacity-60"
      }`}
    >
    <div className="flex min-w-0 items-center gap-3">
      <div className="min-w-0 flex-1">
        <p className="truncate text-sm font-medium text-strong">
          {cred.display_name || cred.account_key}
        </p>
        <div className="mt-0.5 flex flex-wrap gap-x-3 gap-y-0 text-[11px] text-muted">
          <span>key: {cred.account_key}</span>
          {cred.has_api_key && cred.api_key_last_four ? (
            <span className="flex items-center gap-1">
              <KeyRound className="h-3 w-3" />
              ••••{cred.api_key_last_four}
            </span>
          ) : cred.has_api_key ? (
            <span className="flex items-center gap-1">
              <KeyRound className="h-3 w-3" />
              set
            </span>
          ) : (
            <span className="text-[color:var(--warning)]">no key</span>
          )}
          {cred.base_url && <span className="truncate max-w-[200px]">{cred.base_url}</span>}
        </div>
      </div>
      {isAdmin && (
        <div className="flex shrink-0 items-center gap-1.5">
          <button
            type="button"
            onClick={async () => {
              setToggling(true);
              await onToggle(cred);
              setToggling(false);
            }}
            disabled={toggling}
            className={`rounded-full px-2 py-0.5 text-[11px] font-medium transition ${
              cred.active
                ? "bg-[color:rgba(52,211,153,0.15)] text-[color:var(--success)] hover:opacity-80"
                : "bg-[color:var(--surface-strong)] text-muted hover:opacity-80"
            }`}
          >
            {toggling ? "…" : cred.active ? "Active" : "Inactive"}
          </button>
          <Button
            variant="ghost"
            size="sm"
            className="h-7 w-7 p-0 text-[color:var(--danger)] hover:bg-[color:var(--danger-soft)]"
            onClick={() => onDelete(cred)}
          >
            <Trash2 className="h-3.5 w-3.5" />
          </Button>
        </div>
      )}
    </div>
    {showUsage && cred.active && (cred.has_api_key || cred.base_url) && (
      <UsageStrip credentialId={cred.id} provider={cred.provider} />
    )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Provider section
// ---------------------------------------------------------------------------

interface ProviderSectionProps {
  provider: (typeof PROVIDERS)[number];
  credentials: ProviderCredentialRead[];
  isAdmin: boolean;
  onAdd: (providerId: ProviderId, data: { account_key: string; display_name: string; api_key: string; base_url: string }) => Promise<void>;
  onTest: (providerId: ProviderId, data: { account_key: string; api_key: string; base_url: string }) => Promise<ProviderUsageLiveRead>;
  onDelete: (cred: ProviderCredentialRead) => void;
  onToggle: (cred: ProviderCredentialRead) => Promise<void>;
}

function ProviderSection({ provider, credentials, isAdmin, onAdd, onTest, onDelete, onToggle }: ProviderSectionProps) {
  const Icon = provider.icon;
  const [showForm, setShowForm] = useState(false);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);

  const canAdd = isAdmin && (provider.allowMultiple || credentials.length === 0);

  return (
    <section className="rounded-xl border border-[color:var(--border)] bg-[color:var(--surface)] p-4 shadow-lush md:p-5">
      <div className="flex items-start justify-between gap-3">
        <div className="flex min-w-0 items-start gap-3">
          <div className="rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-2 text-[color:var(--accent)] shrink-0">
            <Icon className="h-4 w-4" />
          </div>
          <div className="min-w-0">
            <h2 className="text-base font-semibold text-strong">{provider.label}</h2>
            <p className="mt-0.5 text-sm text-muted">{provider.description}</p>
          </div>
        </div>
        {canAdd && !showForm && (
          <Button
            size="sm"
            variant="outline"
            onClick={() => { setShowForm(true); setSaveError(null); }}
          >
            <Plus className="h-3.5 w-3.5" />
            Add
          </Button>
        )}
      </div>

      {showForm && (
        <CredentialForm
          providerId={provider.id}
          allowMultiple={provider.allowMultiple}
          showBaseUrl={provider.showBaseUrl}
          keyLabel={provider.keyLabel}
          keyPlaceholder={provider.keyPlaceholder}
          accountKeyDefault={provider.accountKeyDefault}
          onSave={async (data) => {
            setSaving(true);
            setSaveError(null);
            try {
              await onAdd(provider.id, data);
              setShowForm(false);
            } catch (err) {
              setSaveError(err instanceof Error ? err.message : "Save failed.");
            } finally {
              setSaving(false);
            }
          }}
          onTest={(data) => onTest(provider.id, data)}
          onCancel={() => setShowForm(false)}
          isSaving={saving}
          error={saveError}
        />
      )}

      {credentials.length > 0 && (
        <div className="mt-3 space-y-2">
          {credentials.map((cred) => (
            <CredentialRow
              key={cred.id}
              cred={cred}
              isAdmin={isAdmin}
              onDelete={onDelete}
              onToggle={onToggle}
            />
          ))}
        </div>
      )}

      {credentials.length === 0 && !showForm && (
        <p className="mt-3 text-sm text-muted">
          No {provider.label} accounts configured.
          {isAdmin ? " Click Add to set one up." : ""}
        </p>
      )}
    </section>
  );
}

// ---------------------------------------------------------------------------
// Page
// ---------------------------------------------------------------------------

export default function AIProvidersSettingsPage() {
  const { isSignedIn } = useAuth();
  const { isAdmin } = useOrganizationMembership(isSignedIn);
  const [credentials, setCredentials] = useState<ProviderCredentialRead[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<ProviderCredentialRead | null>(null);
  const [isDeleting, setIsDeleting] = useState(false);
  const [deleteError, setDeleteError] = useState<string | null>(null);

  const load = useCallback(async () => {
    try {
      setIsLoading(true);
      const res = await listProviderCredentialsApiV1ProviderCredentialsGet();
      if (res.status === 200) setCredentials(res.data);
      setError(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Could not load provider settings.");
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    if (isSignedIn) void load();
  }, [isSignedIn, load]);

  const handleAdd = async (
    providerId: ProviderId,
    data: { account_key: string; display_name: string; api_key: string; base_url: string },
  ) => {
    const res = await createProviderCredentialApiV1ProviderCredentialsPost({
      provider: providerId,
      account_key: data.account_key,
      display_name: data.display_name || data.account_key,
      api_key: data.api_key || undefined,
      base_url: data.base_url || undefined,
    });
    if (res.status === 201) {
      setCredentials((prev) => [...prev, res.data]);
    } else {
      throw new Error("Failed to save credential.");
    }
  };

  const handleTest = async (
    providerId: ProviderId,
    data: { account_key: string; api_key: string; base_url: string },
  ): Promise<ProviderUsageLiveRead> => {
    const response = await customFetch<{
      data: ProviderUsageLiveRead;
      status: number;
      headers: Headers;
    }>("/api/v1/provider-credentials/test", {
      method: "POST",
      body: JSON.stringify({
        provider: providerId,
        account_key: data.account_key || "test",
        api_key: data.api_key || undefined,
        base_url: data.base_url || undefined,
      }),
    });
    return response.data;
  };

  const handleToggle = async (cred: ProviderCredentialRead) => {
    const res = await updateProviderCredentialApiV1ProviderCredentialsCredentialIdPatch(
      cred.id,
      { active: !cred.active },
    );
    if (res.status === 200) {
      setCredentials((prev) => prev.map((c) => (c.id === cred.id ? res.data : c)));
    }
  };

  const handleDelete = async () => {
    if (!deleteTarget) return;
    setIsDeleting(true);
    setDeleteError(null);
    try {
      await deleteProviderCredentialApiV1ProviderCredentialsCredentialIdDelete(deleteTarget.id);
      setCredentials((prev) => prev.filter((c) => c.id !== deleteTarget.id));
      setDeleteTarget(null);
    } catch (err) {
      setDeleteError(err instanceof Error ? err.message : "Delete failed.");
    } finally {
      setIsDeleting(false);
    }
  };

  return (
    <>
      <DashboardPageLayout
        signedOut={{
          message: "Sign in to manage AI provider settings.",
          forceRedirectUrl: "/settings/ai-providers",
          signUpForceRedirectUrl: "/settings/ai-providers",
        }}
        title="AI Providers"
        description="Configure API keys and endpoints for the AI providers your gateway uses."
      >
        {isLoading ? (
          <div className="flex items-center gap-2 rounded-xl border border-[color:var(--border)] bg-[color:var(--surface)] p-6 text-sm text-muted">
            <Loader2 className="h-4 w-4 animate-spin" />
            Loading provider settings…
          </div>
        ) : error ? (
          <div className="rounded-xl border border-[color:rgba(248,113,113,0.35)] bg-[color:rgba(248,113,113,0.08)] p-4 text-sm text-[color:var(--danger)]">
            {error}
          </div>
        ) : (
          <div className="space-y-4">
            {!isAdmin && (
              <div className="rounded-xl border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-3 text-sm text-muted">
                You can view provider settings. Only org admins can add or change credentials.
              </div>
            )}
            {PROVIDERS.map((provider) => (
              <ProviderSection
                key={provider.id}
                provider={provider}
                credentials={credentials.filter((c) => c.provider === provider.id)}
                isAdmin={isAdmin}
                onAdd={handleAdd}
                onTest={handleTest}
                onDelete={setDeleteTarget}
                onToggle={handleToggle}
              />
            ))}
          </div>
        )}
      </DashboardPageLayout>

      <ConfirmActionDialog
        open={Boolean(deleteTarget)}
        onOpenChange={(open) => { if (!open) setDeleteTarget(null); }}
        title="Remove provider account"
        description={
          deleteTarget
            ? `Remove "${deleteTarget.display_name || deleteTarget.account_key}" (${deleteTarget.provider})? The stored key will be deleted and cannot be recovered.`
            : ""
        }
        onConfirm={handleDelete}
        isConfirming={isDeleting}
        errorMessage={deleteError}
        confirmLabel="Remove account"
        confirmingLabel="Removing…"
        confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90"
        cancelLabel="Keep it"
      />
    </>
  );
}
