import { type JSX, useState, useEffect, useRef } from "react";
import { Button } from "../ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
import { Eye, EyeOff, Copy, Check, ChevronDown } from "lucide-react";
import type { ProviderConfig, ProviderModelMetadata } from "../../lib/providerContract";
import { copyTextToClipboard } from "../../lib/clipboard";
import { maskApiKey } from "../../lib/mask";
import { formatContextWindowInput, parseContextWindowTokensInput } from "../../lib/utils";

const ZHIPU_PROVIDER_KEYWORDS = ["zhipu", "zhipuai", "bigmodel", "z.ai", "zai", "glm"];
const ZHIPU_CODING_PROVIDER_KEYWORDS = [
  "zhipu coding",
  "glm coding",
  "bigmodel coding",
  "z.ai coding",
  "zai coding",
];

// Known provider presets - maps provider name keywords to their API URLs
const KNOWN_PROVIDER_PRESETS: Record<
  string,
  { anthropicBaseUrl?: string; openaiBaseUrl?: string; apiDocsUrl?: string }
> = {
  deepseek: {
    openaiBaseUrl: "https://api.deepseek.com",
  },
  minimax: {
    anthropicBaseUrl: "https://api.minimaxi.com/anthropic",
    apiDocsUrl: "https://platform.minimaxi.com/docs/api-reference/api-overview",
  },
  "zhipu coding": {
    anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
    openaiBaseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/coding-plan/quick-start",
  },
  "glm coding": {
    anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
    openaiBaseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/coding-plan/quick-start",
  },
  "bigmodel coding": {
    anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
    openaiBaseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/coding-plan/quick-start",
  },
  "z.ai coding": {
    anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
    openaiBaseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/coding-plan/quick-start",
  },
  "zai coding": {
    anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
    openaiBaseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/coding-plan/quick-start",
  },
  zhipu: {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  zhipuai: {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  bigmodel: {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  "z.ai": {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  zai: {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  glm: {
    openaiBaseUrl: "https://open.bigmodel.cn/api/paas/v4",
    apiDocsUrl: "https://docs.bigmodel.cn/cn/guide/develop/openai/introduction",
  },
  alibaba: {
    openaiBaseUrl: "https://dashscope.aliyuncs.com/compatible-mode",
  },
};

// MiniMax model options
const MINIMAX_MODELS = [
  "MiniMax M3",
  "MiniMax M2.7",
  "MiniMax M2.7-highspeed",
  "MiniMax M2.5",
  "MiniMax M2.5-highspeed",
  "MiniMax M2.1",
  "MiniMax M2.1-highspeed",
  "MiniMax M2",
];

// Alibaba model options
const ALIBABA_MODELS = ["glm-5", "glm-5.1", "glm-5.2", "qwen3.6-plus", "qwen3.7-max"];

// ZhipuAI / Z.AI model options
const ZHIPU_MODELS = [
  "glm-5.2",
  "glm-5.1",
  "glm-5",
  "glm-5-turbo",
  "glm-4.7",
  "glm-4.7-flashx",
  "glm-4.6",
  "glm-4.5",
  "glm-4.5-air",
  "glm-4.5-x",
  "glm-4.5-airx",
  "glm-4.5-flash",
];

type ProviderFormProps = {
  provider?: ProviderConfig;
  onSubmit: (data: {
    name: string;
    apiKey: string;
    models: string[];
    anthropicBaseUrl?: string;
    openaiBaseUrl?: string;
    apiDocsUrl?: string;
    modelMetadataUrl?: string;
    modelMetadata?: ProviderModelMetadata[];
    source?: "company" | "personal";
  }) => void;
  onCancel: () => void;
};

type ModelMetadataDraft = {
  contextWindow: string;
  contextWindowMode: ContextWindowMode;
  outputLimit: string;
};

type ContextWindowMode = "unset" | "preset" | "custom";

type ContextWindowUnit = "K" | "M" | "tokens";

const CONTEXT_WINDOW_UNSET = "__unset__";
const CONTEXT_WINDOW_CUSTOM = "__custom__";

const CONTEXT_WINDOW_PRESETS = [
  { value: "32K", label: "Small" },
  { value: "64K", label: "Standard" },
  { value: "128K", label: "Medium" },
  { value: "200K", label: "Long" },
  { value: "256K", label: "Extended" },
  { value: "512K", label: "Large" },
  { value: "1M", label: "Max" },
];

function emptyMetadataDraft(): ModelMetadataDraft {
  return { contextWindow: "", contextWindowMode: "unset", outputLimit: "" };
}

function normalizeModelName(value: string): string {
  return value.trim().toLowerCase().replace(/\s+/g, "-");
}

function findModelMetadata(
  provider: ProviderConfig | undefined,
  model: string,
): ProviderModelMetadata | null {
  const normalized = normalizeModelName(model);
  return (
    provider?.modelMetadata?.find(
      (metadata) => normalizeModelName(metadata.model) === normalized,
    ) ?? null
  );
}

function findContextWindowPreset(value: string): string | null {
  const tokens = parseContextWindowTokensInput(value);
  if (tokens === null) return null;
  for (const preset of CONTEXT_WINDOW_PRESETS) {
    if (parseContextWindowTokensInput(preset.value) === tokens) return preset.value;
  }
  return null;
}

function contextWindowModeForValue(value: string): ContextWindowMode {
  if (value.trim() === "") return "unset";
  return findContextWindowPreset(value) !== null ? "preset" : "custom";
}

function selectedContextWindowPresetValue(draft: ModelMetadataDraft): string {
  switch (draft.contextWindowMode) {
    case "unset":
      return CONTEXT_WINDOW_UNSET;
    case "custom":
      return CONTEXT_WINDOW_CUSTOM;
    case "preset":
      return findContextWindowPreset(draft.contextWindow) ?? CONTEXT_WINDOW_CUSTOM;
  }
}

function splitContextWindowEditorValue(value: string): { amount: string; unit: ContextWindowUnit } {
  const trimmed = value.trim().replaceAll(",", "");
  if (trimmed === "") return { amount: "", unit: "K" };
  const match = /^(\d+(?:\.\d+)?)\s*([kKmM])?$/.exec(trimmed);
  if (match === null) return { amount: trimmed, unit: "K" };
  const amount = match[1];
  if (amount === undefined) return { amount: trimmed, unit: "K" };
  const unit = match[2];
  if (unit === undefined || unit === "") return { amount, unit: "tokens" };
  switch (unit.toLowerCase()) {
    case "k":
      return { amount, unit: "K" };
    case "m":
      return { amount, unit: "M" };
    default:
      return { amount: trimmed, unit: "K" };
  }
}

function joinContextWindowEditorValue(amount: string, unit: ContextWindowUnit): string {
  const trimmed = amount.trim();
  if (trimmed === "") return "";
  switch (unit) {
    case "K":
      return `${trimmed}K`;
    case "M":
      return `${trimmed}M`;
    case "tokens":
      return trimmed;
  }
}

function createMetadataDrafts(
  provider: ProviderConfig | undefined,
  models: readonly string[],
): ModelMetadataDraft[] {
  return models.map((model) => {
    const metadata = findModelMetadata(provider, model);
    const contextWindow =
      metadata?.contextWindow !== undefined ? formatContextWindowInput(metadata.contextWindow) : "";
    return {
      contextWindow,
      contextWindowMode: contextWindowModeForValue(contextWindow),
      outputLimit: metadata?.outputLimit?.toString() ?? "",
    };
  });
}

function readPositiveIntegerInput(value: string): number | null {
  const trimmed = value.trim();
  if (trimmed === "") return null;
  const parsed = Number(trimmed);
  if (!Number.isInteger(parsed) || parsed <= 0) return null;
  return parsed;
}

export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps): JSX.Element {
  const [name, setName] = useState(provider?.name ?? "");
  const [apiKey, setApiKey] = useState(provider?.apiKey ?? "");
  const [showApiKey, setShowApiKey] = useState(false);
  const [copied, setCopied] = useState(false);
  const initialModels = provider?.models;
  const [models, setModels] = useState<string[]>(
    initialModels !== undefined && initialModels.length > 0 ? initialModels : [""],
  );
  const [modelMetadataDrafts, setModelMetadataDrafts] = useState<ModelMetadataDraft[]>(() =>
    createMetadataDrafts(
      provider,
      initialModels !== undefined && initialModels.length > 0 ? initialModels : [""],
    ),
  );
  const [activeTab, setActiveTab] = useState<"anthropic" | "openai">("anthropic");
  const [anthropicBaseUrl, setAnthropicBaseUrl] = useState(provider?.anthropicBaseUrl ?? "");
  const [openaiBaseUrl, setOpenaiBaseUrl] = useState(provider?.openaiBaseUrl ?? "");
  const [apiDocsUrl, setApiDocsUrl] = useState(provider?.apiDocsUrl ?? "");
  const [modelMetadataUrl, setModelMetadataUrl] = useState(provider?.modelMetadataUrl ?? "");
  const [source, setSource] = useState<"company" | "personal" | undefined>(provider?.source);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [openModelDropdown, setOpenModelDropdown] = useState<number | null>(null);
  const modelRowRefs = useRef<(HTMLDivElement | null)[]>([]);

  // Close model dropdown when clicking outside
  useEffect(() => {
    if (openModelDropdown === null) return;
    const index = openModelDropdown;
    function handleClick(e: MouseEvent) {
      if (!(e.target instanceof Node)) return;
      const ref = modelRowRefs.current[index];
      if (ref !== null && ref !== undefined && !ref.contains(e.target)) {
        setOpenModelDropdown(null);
      }
    }
    document.addEventListener("mousedown", handleClick);
    return () => document.removeEventListener("mousedown", handleClick);
  }, [openModelDropdown]);

  // Track if URL fields have been manually edited (to avoid overriding user edits)
  const [manualAnthropicUrlOverride, setManualAnthropicUrlOverride] = useState(false);
  const [manualOpenaiUrlOverride, setManualOpenaiUrlOverride] = useState(false);

  // Check if MiniMax is detected
  const isMiniMax = name.toLowerCase().includes("minimax");
  // Check if Alibaba is detected
  const isAlibaba = name.toLowerCase().includes("alibaba");
  const isZhipu = [...ZHIPU_PROVIDER_KEYWORDS, ...ZHIPU_CODING_PROVIDER_KEYWORDS].some((keyword) =>
    name.toLowerCase().includes(keyword),
  );
  const suggestedModels = isMiniMax
    ? MINIMAX_MODELS
    : isZhipu
      ? ZHIPU_MODELS
      : isAlibaba
        ? ALIBABA_MODELS
        : [];
  const hasContextMetadata =
    provider?.modelMetadata?.some((metadata) => metadata.contextWindow !== undefined) ?? false;

  function handleCopy() {
    void copyTextToClipboard(apiKey).then((success) => {
      if (!success) return;
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  }

  useEffect(() => {
    if (provider) {
      setName(provider.name);
      setApiKey(provider.apiKey);
      const nextModels = (provider.models?.length ?? 0) > 0 ? provider.models : [""];
      setModels(nextModels);
      setModelMetadataDrafts(createMetadataDrafts(provider, nextModels));
      setAnthropicBaseUrl(provider.anthropicBaseUrl ?? "");
      setOpenaiBaseUrl(provider.openaiBaseUrl ?? "");
      setApiDocsUrl(provider.apiDocsUrl ?? "");
      setModelMetadataUrl(provider.modelMetadataUrl ?? "");
      setSource(provider.source);
      setManualAnthropicUrlOverride(false);
      setManualOpenaiUrlOverride(false);
    }
  }, [provider]);

  // Detect known provider presets and auto-fill URLs
  useEffect(() => {
    const lowerName = name.toLowerCase();
    for (const [keyword, preset] of Object.entries(KNOWN_PROVIDER_PRESETS)) {
      if (lowerName.includes(keyword)) {
        if (preset.anthropicBaseUrl !== undefined && !manualAnthropicUrlOverride) {
          setAnthropicBaseUrl(preset.anthropicBaseUrl);
        }
        if (preset.openaiBaseUrl !== undefined && !manualOpenaiUrlOverride) {
          setOpenaiBaseUrl(preset.openaiBaseUrl);
        }
        if (preset.apiDocsUrl !== undefined && !apiDocsUrl) {
          setApiDocsUrl(preset.apiDocsUrl);
        }
        // For MiniMax, auto-select the first model if not already set
        if (keyword === "minimax" && models.length === 1 && models[0] === "") {
          setModels([MINIMAX_MODELS[0] ?? ""]);
        }
        // For Alibaba, auto-select the first model if not already set
        if (keyword === "alibaba" && models.length === 1 && models[0] === "") {
          setModels([ALIBABA_MODELS[0] ?? ""]);
        }
        // For ZhipuAI, auto-select the first model if not already set
        if (
          (ZHIPU_PROVIDER_KEYWORDS.includes(keyword) ||
            ZHIPU_CODING_PROVIDER_KEYWORDS.includes(keyword)) &&
          models.length === 1 &&
          models[0] === ""
        ) {
          setModels([ZHIPU_MODELS[0] ?? ""]);
        }
        break;
      }
    }
  }, [name]);

  function validate(): boolean {
    const newErrors: Record<string, string> = {};
    if (!name.trim()) {
      newErrors.name = "Name is required";
    }
    if (!apiKey.trim()) {
      newErrors.apiKey = "API key is required";
    }
    if (models.length === 0 || models.every((m) => !m.trim())) {
      newErrors.models = "At least one model is required";
    }
    if (anthropicBaseUrl.trim() && !isValidUrl(anthropicBaseUrl.trim())) {
      newErrors.anthropicBaseUrl = "Invalid URL format";
    }
    if (openaiBaseUrl.trim() && !isValidUrl(openaiBaseUrl.trim())) {
      newErrors.openaiBaseUrl = "Invalid URL format";
    }
    if (modelMetadataUrl.trim() && !isValidUrl(modelMetadataUrl.trim())) {
      newErrors.modelMetadataUrl = "Invalid URL format";
    }
    modelMetadataDrafts.forEach((draft, index) => {
      const contextWindow = parseContextWindowTokensInput(draft.contextWindow);
      const outputLimit = readPositiveIntegerInput(draft.outputLimit);
      if (draft.contextWindow.trim() !== "" && contextWindow === null) {
        newErrors[`modelMetadata.${index}.contextWindow`] =
          "Context window must be a positive number, optionally using K or M";
      }
      if (draft.outputLimit.trim() !== "" && outputLimit === null) {
        newErrors[`modelMetadata.${index}.outputLimit`] = "Output limit must be a positive integer";
      }
      if (contextWindow !== null && outputLimit !== null && outputLimit > contextWindow) {
        newErrors[`modelMetadata.${index}.outputLimit`] =
          "Output limit should not exceed context window";
      }
    });
    if (!anthropicBaseUrl.trim() && !openaiBaseUrl.trim()) {
      newErrors.format = "At least one format URL (Anthropic or OpenAI) is required";
    }
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  }

  function isValidUrl(str: string): boolean {
    try {
      new URL(str);
      return true;
    } catch {
      return false;
    }
  }

  function updateModel(index: number, value: string): void {
    setModels((prev) => {
      const next = [...prev];
      next[index] = value;
      return next;
    });
  }

  function updateMetadataDraft(index: number, patch: Partial<ModelMetadataDraft>): void {
    setModelMetadataDrafts((prev) => {
      const next = [...prev];
      next[index] = { ...(next[index] ?? emptyMetadataDraft()), ...patch };
      return next;
    });
  }

  function updateContextWindowPreset(index: number, value: string): void {
    switch (value) {
      case CONTEXT_WINDOW_UNSET:
        updateMetadataDraft(index, { contextWindow: "", contextWindowMode: "unset" });
        return;
      case CONTEXT_WINDOW_CUSTOM: {
        const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
        updateMetadataDraft(index, {
          contextWindow: current.contextWindow,
          contextWindowMode: "custom",
        });
        return;
      }
      default:
        updateMetadataDraft(index, { contextWindow: value, contextWindowMode: "preset" });
        return;
    }
  }

  function updateContextWindowAmount(index: number, amount: string): void {
    const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
    const editorValue = splitContextWindowEditorValue(current.contextWindow);
    updateMetadataDraft(index, {
      contextWindow: joinContextWindowEditorValue(amount, editorValue.unit),
      contextWindowMode: "custom",
    });
  }

  function updateContextWindowUnit(index: number, unit: string): void {
    const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
    const editorValue = splitContextWindowEditorValue(current.contextWindow);
    switch (unit) {
      case "K":
      case "M":
      case "tokens":
        updateMetadataDraft(index, {
          contextWindow: joinContextWindowEditorValue(editorValue.amount, unit),
          contextWindowMode: "custom",
        });
        return;
      default:
        return;
    }
  }

  function removeModel(index: number): void {
    setModels((prev) => prev.filter((_, idx) => idx !== index));
    setModelMetadataDrafts((prev) => prev.filter((_, idx) => idx !== index));
  }

  function addModel(): void {
    setModels((prev) => [...prev, ""]);
    setModelMetadataDrafts((prev) => [...prev, emptyMetadataDraft()]);
  }

  function buildModelMetadata(): ProviderModelMetadata[] | undefined {
    const now = new Date().toISOString();
    const metadata: ProviderModelMetadata[] = [];

    models.forEach((model, index) => {
      const trimmedModel = model.trim();
      if (trimmedModel === "") return;
      const draft = modelMetadataDrafts[index] ?? emptyMetadataDraft();
      const contextWindow = parseContextWindowTokensInput(draft.contextWindow);
      const outputLimit = readPositiveIntegerInput(draft.outputLimit);
      if (contextWindow === null && outputLimit === null) return;

      const existing = findModelMetadata(provider, trimmedModel);
      if (
        existing !== null &&
        existing.contextWindow === (contextWindow ?? undefined) &&
        existing.outputLimit === (outputLimit ?? undefined)
      ) {
        metadata.push({ ...existing, model: trimmedModel });
        return;
      }

      const entry: ProviderModelMetadata = {
        model: trimmedModel,
        source: "manual",
        updatedAt: now,
      };
      if (contextWindow !== null) entry.contextWindow = contextWindow;
      if (outputLimit !== null) entry.outputLimit = outputLimit;
      metadata.push(entry);
    });

    if (metadata.length > 0) return metadata;
    return provider?.modelMetadata !== undefined ? [] : undefined;
  }

  function handleSubmit(e: React.FormEvent): void {
    e.preventDefault();
    if (!validate()) return;
    setIsSubmitting(true);
    try {
      onSubmit({
        name: name.trim(),
        apiKey: apiKey.trim(),
        models: models.map((m) => m.trim()).filter((m) => m !== ""),
        anthropicBaseUrl: anthropicBaseUrl.trim() || undefined,
        openaiBaseUrl: openaiBaseUrl.trim() || undefined,
        apiDocsUrl: apiDocsUrl.trim() || undefined,
        modelMetadataUrl: modelMetadataUrl.trim() || undefined,
        modelMetadata: buildModelMetadata(),
        source,
      });
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div className="space-y-2">
        <label htmlFor="provider-name" className="text-sm font-medium">
          Name <span className="text-destructive">*</span>
        </label>
        <input
          id="provider-name"
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Provider Name"
          className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
        />
        {errors.name !== undefined && <p className="text-xs text-destructive">{errors.name}</p>}
      </div>

      <div className="space-y-2">
        <label htmlFor="provider-source" className="text-sm font-medium">
          Token Source
        </label>
        <select
          id="provider-source"
          value={source ?? ""}
          onChange={(e) =>
            setSource(
              e.target.value === "company" || e.target.value === "personal"
                ? e.target.value
                : undefined,
            )
          }
          className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
        >
          <option value="">—</option>
          <option value="personal">个人 (Personal)</option>
          <option value="company">公司 (Company)</option>
        </select>
        <p className="text-xs text-muted-foreground">
          Label whether this API key is company-provided or personal.
        </p>
      </div>

      <div className="space-y-2">
        <label htmlFor="provider-model-metadata-url" className="text-sm font-medium">
          Model Metadata URL
        </label>
        <input
          id="provider-model-metadata-url"
          type="text"
          value={modelMetadataUrl}
          onChange={(e) => setModelMetadataUrl(e.target.value)}
          placeholder="https://example.com/agent-inspector-models.json"
          className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
        />
        {errors.modelMetadataUrl !== undefined && (
          <p className="text-xs text-destructive">{errors.modelMetadataUrl}</p>
        )}
        {modelMetadataUrl.trim() === "" && (
          <div className="rounded-md border border-border bg-muted/20 px-3 py-2 text-xs text-muted-foreground">
            Built-in limits cover DeepSeek v4 pro/flash, MiniMax M3/M2.7/M2.5/M2.1, and GLM coding
            models. Use a registry URL for private or custom model limits.
          </div>
        )}
        {provider !== undefined && !hasContextMetadata && modelMetadataUrl.trim() === "" && (
          <p className="text-xs text-amber-400">
            This provider has no matching context metadata yet.
          </p>
        )}
        {modelMetadataUrl.trim() !== "" && (
          <p className="text-xs text-muted-foreground">
            Agent Inspector will refresh model limits from this JSON registry after save.
          </p>
        )}
      </div>

      <div className="space-y-2">
        <label htmlFor="provider-apikey" className="text-sm font-medium">
          API Key <span className="text-destructive">*</span>
        </label>
        <div className="flex items-center gap-2">
          <input
            id="provider-apikey"
            type="text"
            value={showApiKey || apiKey.length === 0 ? apiKey : maskApiKey(apiKey)}
            onChange={(e) => setApiKey(e.target.value)}
            onFocus={() => {
              if (!showApiKey && apiKey.length > 0) setShowApiKey(true);
            }}
            placeholder="sk-ant-..."
            readOnly={!showApiKey && apiKey.length > 0}
            className="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
          />
          <button
            type="button"
            onClick={() => setShowApiKey((s) => !s)}
            className="text-muted-foreground hover:text-foreground transition-colors p-1 shrink-0"
            aria-label={showApiKey ? "Hide API key" : "Show API key"}
          >
            {showApiKey ? <EyeOff className="size-4" /> : <Eye className="size-4" />}
          </button>
          <button
            type="button"
            onClick={handleCopy}
            className="text-muted-foreground hover:text-foreground transition-colors p-1 shrink-0"
            aria-label="Copy API key"
          >
            {copied ? <Check className="size-4 text-green-500" /> : <Copy className="size-4" />}
          </button>
        </div>
        {errors.apiKey !== undefined && <p className="text-xs text-destructive">{errors.apiKey}</p>}
      </div>

      <div className="space-y-2">
        <label className="text-sm font-medium">
          Models <span className="text-destructive">*</span>
        </label>
        {models.map((m, i) => {
          const draft = modelMetadataDrafts[i] ?? emptyMetadataDraft();
          const contextWindowError = errors[`modelMetadata.${i}.contextWindow`];
          const outputLimitError = errors[`modelMetadata.${i}.outputLimit`];
          const contextWindowPresetValue = selectedContextWindowPresetValue(draft);
          const contextWindowEditorValue = splitContextWindowEditorValue(draft.contextWindow);
          return (
            <div
              key={i}
              ref={(el) => {
                modelRowRefs.current[i] = el;
              }}
              className="space-y-2 rounded-md border border-border bg-muted/10 p-2"
            >
              <div className="flex items-center gap-2">
                <div className="relative flex-1">
                  <input
                    type="text"
                    value={m}
                    onChange={(e) => updateModel(i, e.target.value)}
                    placeholder={
                      suggestedModels.length > 0 ? "Type or select a model..." : "Model name"
                    }
                    className="w-full rounded-md border border-input bg-background px-4 py-3 pr-8 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
                  />
                  {suggestedModels.length > 0 && (
                    <>
                      <button
                        type="button"
                        onClick={() => setOpenModelDropdown(openModelDropdown === i ? null : i)}
                        className="absolute right-1 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors p-1 z-10"
                        aria-label="Show model suggestions"
                      >
                        <ChevronDown className="size-4" />
                      </button>
                      {openModelDropdown === i && (
                        <div className="absolute left-0 right-0 top-full mt-1 z-50 bg-popover border border-border rounded-md shadow-md max-h-48 overflow-y-auto">
                          {suggestedModels.map((opt) => (
                            <button
                              key={opt}
                              type="button"
                              onClick={() => {
                                updateModel(i, opt);
                                setOpenModelDropdown(null);
                              }}
                              className="w-full text-left px-3 py-2 text-sm hover:bg-muted transition-colors"
                            >
                              {opt}
                            </button>
                          ))}
                        </div>
                      )}
                    </>
                  )}
                </div>
                {models.length > 1 && (
                  <button
                    type="button"
                    onClick={() => removeModel(i)}
                    className="text-muted-foreground hover:text-destructive transition-colors p-1 shrink-0"
                    aria-label="Remove model"
                  >
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="16"
                      height="16"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      strokeWidth="2"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                    >
                      <path d="M3 6h18" />
                      <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
                      <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
                    </svg>
                  </button>
                )}
              </div>

              <div className="grid gap-2 sm:grid-cols-2">
                <div className="space-y-1 text-xs text-muted-foreground">
                  <span>Context Window</span>
                  <Select
                    value={contextWindowPresetValue}
                    onValueChange={(value) => updateContextWindowPreset(i, value)}
                  >
                    <SelectTrigger size="sm" className="w-full bg-background font-mono text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent className="max-h-64">
                      <SelectItem value={CONTEXT_WINDOW_UNSET}>Not set</SelectItem>
                      {CONTEXT_WINDOW_PRESETS.map((preset) => (
                        <SelectItem key={preset.value} value={preset.value}>
                          {preset.label} · {preset.value}
                        </SelectItem>
                      ))}
                      <SelectItem value={CONTEXT_WINDOW_CUSTOM}>Custom</SelectItem>
                    </SelectContent>
                  </Select>
                  {draft.contextWindowMode === "custom" && (
                    <div className="grid grid-cols-[minmax(0,1fr)_5.75rem] gap-1.5">
                      <input
                        type="text"
                        inputMode="decimal"
                        value={contextWindowEditorValue.amount}
                        onChange={(e) => updateContextWindowAmount(i, e.target.value)}
                        placeholder="128"
                        className="w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px]"
                      />
                      <Select
                        value={contextWindowEditorValue.unit}
                        onValueChange={(value) => updateContextWindowUnit(i, value)}
                      >
                        <SelectTrigger size="sm" className="w-full bg-background font-mono text-xs">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="K">K</SelectItem>
                          <SelectItem value="M">M</SelectItem>
                          <SelectItem value="tokens">tokens</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>
                  )}
                  {contextWindowError !== undefined && (
                    <span className="block text-destructive">{contextWindowError}</span>
                  )}
                </div>
                <label className="space-y-1 text-xs text-muted-foreground">
                  <span>Output Limit</span>
                  <input
                    type="number"
                    min={1}
                    step={1000}
                    value={draft.outputLimit}
                    onChange={(e) => updateMetadataDraft(i, { outputLimit: e.target.value })}
                    placeholder="e.g. 8192"
                    className="w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px]"
                  />
                  {outputLimitError !== undefined && (
                    <span className="block text-destructive">{outputLimitError}</span>
                  )}
                </label>
              </div>
            </div>
          );
        })}
        <button
          type="button"
          onClick={addModel}
          className="text-xs text-primary hover:underline flex items-center gap-1"
        >
          + Add Model
        </button>
        {errors.models !== undefined && <p className="text-xs text-destructive">{errors.models}</p>}
      </div>

      <div className="space-y-2">
        <div className="flex gap-1 border-b border-border">
          <TooltipProvider>
            <Tooltip>
              <TooltipTrigger asChild>
                <button
                  type="button"
                  onClick={() => setActiveTab("anthropic")}
                  className={`px-3 py-2 text-sm font-medium border-b-2 transition-colors ${
                    activeTab === "anthropic"
                      ? "border-primary text-primary"
                      : "border-transparent text-muted-foreground hover:text-foreground"
                  }`}
                >
                  Anthropic Format
                </button>
              </TooltipTrigger>
              <TooltipContent>Anthropic Messages API format</TooltipContent>
            </Tooltip>
          </TooltipProvider>
          <TooltipProvider>
            <Tooltip>
              <TooltipTrigger asChild>
                <button
                  type="button"
                  onClick={() => setActiveTab("openai")}
                  className={`px-3 py-2 text-sm font-medium border-b-2 transition-colors ${
                    activeTab === "openai"
                      ? "border-primary text-primary"
                      : "border-transparent text-muted-foreground hover:text-foreground"
                  }`}
                >
                  OpenAI Format
                </button>
              </TooltipTrigger>
              <TooltipContent>OpenAI Chat Completions API format</TooltipContent>
            </Tooltip>
          </TooltipProvider>
        </div>
        {errors.format !== undefined && <p className="text-xs text-destructive">{errors.format}</p>}
      </div>

      {activeTab === "anthropic" && (
        <div className="space-y-2">
          <label htmlFor="provider-anthropic-base-url" className="text-sm font-medium">
            Anthropic Base URL
          </label>
          <input
            id="provider-anthropic-base-url"
            type="text"
            value={anthropicBaseUrl}
            onChange={(e) => {
              setManualAnthropicUrlOverride(true);
              setAnthropicBaseUrl(e.target.value);
            }}
            placeholder="https://api.anthropic.com"
            className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
          />
          {errors.anthropicBaseUrl !== undefined && (
            <p className="text-xs text-destructive">{errors.anthropicBaseUrl}</p>
          )}
          <p className="text-xs text-muted-foreground">
            Anthropic-compatible endpoint URL. Leave empty if this provider does not support
            Anthropic format.
          </p>
        </div>
      )}

      {activeTab === "openai" && (
        <div className="space-y-2">
          <label htmlFor="provider-openai-base-url" className="text-sm font-medium">
            OpenAI Base URL
          </label>
          <input
            id="provider-openai-base-url"
            type="text"
            value={openaiBaseUrl}
            onChange={(e) => {
              setManualOpenaiUrlOverride(true);
              setOpenaiBaseUrl(e.target.value);
            }}
            placeholder="https://api.openai.com/v1"
            className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
          />
          {errors.openaiBaseUrl !== undefined && (
            <p className="text-xs text-destructive">{errors.openaiBaseUrl}</p>
          )}
          <p className="text-xs text-muted-foreground">
            OpenAI-compatible endpoint URL. Leave empty if this provider does not support OpenAI
            format.
          </p>
        </div>
      )}

      <div className="space-y-2">
        <label htmlFor="provider-api-docs-url" className="text-sm font-medium">
          API Docs URL
        </label>
        <input
          id="provider-api-docs-url"
          type="text"
          value={apiDocsUrl}
          onChange={(e) => setApiDocsUrl(e.target.value)}
          placeholder="https://api.example.com/docs"
          className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
        />
        <p className="text-xs text-muted-foreground">
          Optional API documentation URL. If not set, uses known provider docs.
        </p>
      </div>

      <div className="sticky bottom-0 bg-card border-t flex gap-2 justify-end pt-2 pb-2">
        <Button type="button" variant="outline" onClick={onCancel} disabled={isSubmitting}>
          Cancel
        </Button>
        <Button type="submit" disabled={isSubmitting}>
          {isSubmitting ? "Saving..." : provider ? "Update Provider" : "Add Provider"}
        </Button>
      </div>
    </form>
  );
}
