import * as React from "react";
import { useTranslation } from "react-i18next";
import {
  Bot,
  RefreshCw,
  Search,
  Sparkles,
  Trash2,
} from "lucide-react";
import { createAgentConfig, deleteAgent, listAgentConfigs, listAgentRuns, listModels, listSkills, updateAgent } from "@/api";
import { translateApiError } from "@/api/errors";
import { ApiErrorState } from "@/components/shared/ApiErrorState";
import { ConfirmDialog } from "@/components/shared/ConfirmDialog";
import { EmptyState } from "@/components/shared/EmptyState";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { PageHeader } from "@/components/shared/PageHeader";
import { SearchInput } from "@/components/shared/SearchInput";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog } from "@/components/ui/dialog";
import { Input, Textarea } from "@/components/ui/input";
import { Select } from "@/components/ui/select";
import { toast } from "@/components/ui/toaster";
import { demoText } from "@/lib/demo-text";
import { useAgentList } from "@/hooks";
import type { AgentConfig, AgentDefinition, AgentRun, JSONObject, ModelDefinition, SkillDefinition } from "@/types";
import { AgentOverview } from "./components/AgentOverview";
import { AgentRuns } from "./components/AgentRuns";
import { CreateAgentDialog } from "./components/CreateAgentDialog";

export function AgentListPage() {
  const { t } = useTranslation();
  const [search, setSearch] = React.useState("");
  const [selectedAgentId, setSelectedAgentId] = React.useState<string>();
  const [configs, setConfigs] = React.useState<AgentConfig[]>([]);
  const [runs, setRuns] = React.useState<AgentRun[]>([]);
  const [skills, setSkills] = React.useState<SkillDefinition[]>([]);
  const [relatedLoading, setRelatedLoading] = React.useState(true);
  const [directoryLoading, setDirectoryLoading] = React.useState(false);
  const [editOpen, setEditOpen] = React.useState(false);
  const [deleteOpen, setDeleteOpen] = React.useState(false);
  const [detailTab, setDetailTab] = React.useState<"overview" | "test">("overview");
  const agents = useAgentList();

  const agentList = agents.data ?? [];
  const selectedAgent = agentList.find((agent) => agent.id === selectedAgentId) ?? agentList[0];
  const selectedConfigs = configs.filter((config) => config.agent_id === selectedAgent?.id);
  const selectedRuns = runs
    .filter((r) => r.agent_id === selectedAgent?.id)
    .sort((a, b) => new Date(b.created_time).getTime() - new Date(a.created_time).getTime());
  const activeConfig = [...selectedConfigs].sort((a, b) => new Date(b.created_time).getTime() - new Date(a.created_time).getTime())[0];
  const configByAgent = React.useMemo(() => {
    const grouped = new Map<string, AgentConfig[]>();
    configs.forEach((config) => {
      grouped.set(config.agent_id, [...(grouped.get(config.agent_id) ?? []), config]);
    });
    const result = new Map<string, AgentConfig>();
    grouped.forEach((items, agentId) => {
      const config = [...items].sort((a, b) => new Date(b.created_time).getTime() - new Date(a.created_time).getTime())[0];
      if (config) result.set(agentId, config);
    });
    return result;
  }, [configs]);
  const runsByAgent = React.useMemo(() => {
    const result = new Map<string, AgentRun[]>();
    runs.forEach((run) => {
      result.set(run.agent_id, [...(result.get(run.agent_id) ?? []), run]);
    });
    return result;
  }, [runs]);

  const filtered = agentList.filter((agent) => {
    const text = `${agent.name} ${agent.description ?? ""}`.toLowerCase();
    return text.includes(search.toLowerCase());
  });

  const loadSkills = React.useCallback(async () => {
    try {
      setSkills(await listSkills());
    } catch {
      setSkills([]);
    }
  }, []);

  const loadRelated = React.useCallback(async (agentId?: string, options?: { silent?: boolean }) => {
    if (!agentId) {
      setConfigs([]);
      setRuns([]);
      setRelatedLoading(false);
      return;
    }
    if (!options?.silent) setRelatedLoading(true);
    try {
      const [configData, runData] = await Promise.all([listAgentConfigs(agentId), listAgentRuns(agentId)]);
      setConfigs((current) => [...current.filter((config) => config.agent_id !== agentId), ...configData]);
      setRuns((current) => [...current.filter((run) => run.agent_id !== agentId), ...runData]);
    } catch {
      toast.error(t("errors.failedToLoad"));
    } finally {
      if (!options?.silent) setRelatedLoading(false);
    }
  }, [t]);

  const loadDirectorySummaries = React.useCallback(async (agentIds: string[]) => {
    if (!agentIds.length) return;
    setDirectoryLoading(true);
    try {
      const [configResults, runResults] = await Promise.all([
        Promise.allSettled(agentIds.map((agentId) => listAgentConfigs(agentId))),
        Promise.allSettled(agentIds.map((agentId) => listAgentRuns(agentId))),
      ]);
      const nextConfigs = configResults.flatMap((result) => result.status === "fulfilled" ? result.value : []);
      const nextRuns = runResults.flatMap((result) => result.status === "fulfilled" ? result.value : []);
      setConfigs((current) => [
        ...current.filter((config) => !agentIds.includes(config.agent_id)),
        ...nextConfigs,
      ]);
      setRuns((current) => [
        ...current.filter((run) => !agentIds.includes(run.agent_id)),
        ...nextRuns,
      ]);
    } finally {
      setDirectoryLoading(false);
    }
  }, []);

  React.useEffect(() => { void loadSkills(); }, [loadSkills]);
  React.useEffect(() => { void loadDirectorySummaries(agentList.map((agent) => agent.id)); }, [agentList, loadDirectorySummaries]);
  React.useEffect(() => { void loadRelated(selectedAgent?.id); }, [loadRelated, selectedAgent?.id]);
  React.useEffect(() => { if (!selectedAgentId && agentList[0]) setSelectedAgentId(agentList[0].id); }, [agentList, selectedAgentId]);
  React.useEffect(() => { setDetailTab("overview"); }, [selectedAgent?.id]);

  async function handleDelete() {
    if (!selectedAgent) return;
    try {
      await deleteAgent(selectedAgent.id);
      toast.success(t("agents.agentDeleted"));
      setSelectedAgentId(undefined);
      setDeleteOpen(false);
      void agents.refetch();
    } catch {
      toast.error(t("agents.failedToDeleteAgent"));
    }
  }

  if (agents.loading) return <LoadingSpinner label={t("common.loading")} />;
  if (agents.error) return <ApiErrorState message={agents.error.message} onRetry={() => void agents.refetch()} />;

  return (
    <div className="space-y-6">
      <PageHeader
        title={t("agents.title")}
        description={t("agents.description")}
        actions={
          <>
            <Button variant="outline" onClick={() => { void agents.refetch(); void loadSkills(); void loadRelated(selectedAgent?.id); }}>
              <RefreshCw className="h-4 w-4" /> {t("common.refresh")}
            </Button>
            <CreateAgentDialog onCreated={() => void agents.refetch()} />
          </>
        }
      />

      <div className="grid gap-6 xl:grid-cols-[380px_minmax(0,1fr)]">
        <Card className="overflow-hidden">
          <CardHeader className="border-b border-border">
            <div className="flex items-start justify-between gap-3">
              <div>
                <CardTitle>{t("agents.agentDirectory")}</CardTitle>
                <CardDescription>
                  {directoryLoading ? t("common.loading") : t("agents.shown", { shown: filtered.length, total: agentList.length })}
                </CardDescription>
              </div>
              <Badge className="border-primary/20 bg-primary/10 text-primary">{agentList.length}</Badge>
            </div>
          </CardHeader>
          <CardContent className="space-y-3 pt-4">
            <SearchInput className="sm:w-full" value={search} onChange={setSearch} placeholder={t("agents.searchPlaceholder")} />
            {filtered.length ? (
              <div className="space-y-2">
                {filtered.map((agent) => (
                  <AgentDirectoryRow
                    key={agent.id}
                    active={agent.id === selectedAgent?.id}
                    agent={agent}
                    config={configByAgent.get(agent.id)}
                    runs={runsByAgent.get(agent.id) ?? []}
                    onClick={() => setSelectedAgentId(agent.id)}
                  />
                ))}
              </div>
            ) : (
              <EmptyState icon={Search} title={t("agents.noMatchingAgents")} description={t("agents.adjustFiltersAgent")} />
            )}
          </CardContent>
        </Card>

        <Card className="overflow-hidden">
          <CardHeader className="border-b border-border">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
              <div className="min-w-0">
                <div className="flex flex-wrap items-center gap-2">
                  <Bot className="h-5 w-5 text-primary" />
                  <CardTitle className="truncate">{selectedAgent ? demoText(selectedAgent.name, t) : t("agents.agentDetails")}</CardTitle>
                </div>
                <CardDescription className="mt-2">
                  {selectedAgent ? t("agents.manageDescription") : t("agents.selectAgent")}
                </CardDescription>
              </div>
              {selectedAgent && (
                <div className="flex shrink-0 items-center gap-2">
                  <Button variant="outline" size="sm" onClick={() => setEditOpen(true)}>
                    {t("common.edit")}
                  </Button>
                  <Button variant="ghost" size="sm" onClick={() => setDeleteOpen(true)}>
                    <Trash2 className="h-3 w-3 text-destructive" />
                  </Button>
                </div>
              )}
            </div>
          </CardHeader>
          <CardContent className="min-w-0 pt-4">
            {selectedAgent ? (
              <div className="min-w-0 space-y-4">
                <div className="grid rounded-lg border border-border bg-muted/25 p-1 sm:w-fit sm:grid-cols-2">
                  <button
                    type="button"
                    onClick={() => setDetailTab("overview")}
                    className={[
                      "rounded-md px-4 py-2 text-sm font-medium transition",
                      detailTab === "overview" ? "bg-surface text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
                    ].join(" ")}
                  >
                    {t("agents.overview")}
                  </button>
                  <button
                    type="button"
                    onClick={() => setDetailTab("test")}
                    className={[
                      "rounded-md px-4 py-2 text-sm font-medium transition",
                      detailTab === "test" ? "bg-surface text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
                    ].join(" ")}
                  >
                    {t("agents.test")}
                  </button>
                </div>

                {detailTab === "overview" ? (
                  <AgentOverview
                    agent={selectedAgent}
                    activeConfig={activeConfig}
                    skills={skills}
                    runCount={selectedRuns.length}
                    failedRunCount={selectedRuns.filter((r) => r.status === "failed").length}
                  />
                ) : (
                  <AgentRuns
                    agentId={selectedAgent.id}
                    agentConfigId={activeConfig?.id}
                    runs={selectedRuns}
                    loading={relatedLoading}
                    onRunCompleted={() => void loadRelated(selectedAgent.id, { silent: true })}
                  />
                )}
              </div>
            ) : (
              <EmptyState icon={Bot} title={t("agents.noAgents")} description={t("agents.createAgentStart")} />
            )}
          </CardContent>
        </Card>
      </div>

      {selectedAgent && (
        <EditAgentDialog
          agent={selectedAgent}
          activeConfig={activeConfig}
          open={editOpen}
          onOpenChange={setEditOpen}
          onSaved={() => { void agents.refetch(); void loadRelated(selectedAgent.id); }}
        />
      )}
      <ConfirmDialog
        open={deleteOpen}
        onOpenChange={setDeleteOpen}
        title={t("agents.deleteAgent")}
        description={t("agents.deleteConfirm", { name: demoText(selectedAgent?.name, t) })}
        onConfirm={handleDelete}
      />
    </div>
  );
}

function AgentDirectoryRow({
  agent,
  config,
  active,
  runs,
  onClick,
}: {
  agent: AgentDefinition;
  config?: AgentConfig;
  active: boolean;
  runs: AgentRun[];
  onClick: () => void;
}) {
  const { t } = useTranslation();
  const model = config ? formatAgentModel(config, t) : t("agents.noModelSelected");
  const provider = config ? formatAgentProvider(config, t) : t("agents.providerNotSet");
  const skillCount = config?.skill_refs_json.length ?? 0;
  const failedCount = runs.filter((run) => run.status === "failed").length;
  const latestRun = [...runs].sort((a, b) => new Date(b.created_time).getTime() - new Date(a.created_time).getTime())[0];
  return (
    <button
      type="button"
      onClick={onClick}
      className={[
        "grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 rounded-md border p-3 text-left transition",
        active ? "border-primary/45 bg-primary/10" : "border-border bg-muted/30 hover:bg-muted/55",
      ].join(" ")}
    >
      <span className="min-w-0">
        <span className="block truncate text-sm font-medium">{demoText(agent.name, t)}</span>
        <span className="mt-1 block truncate text-xs text-muted-foreground">
          {model}
          {provider ? ` · ${provider}` : ""}
        </span>
        <span className="mt-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
          <span>{t("agents.runsBadge", { count: runs.length })}</span>
          <span className="text-border">|</span>
          <span>{t("agents.skillsBadge", { count: skillCount })}</span>
          {failedCount ? (
            <>
              <span className="text-border">|</span>
              <span>{t("agents.failedRuns")}: {failedCount}</span>
            </>
          ) : null}
          {latestRun ? (
            <>
              <span className="text-border">|</span>
              <span>{t("agents.latest")}: {readableAgentValue(latestRun.status, t)}</span>
            </>
          ) : null}
        </span>
      </span>
    </button>
  );
}

function formatAgentModel(config: AgentConfig, t: ReturnType<typeof useTranslation>["t"]) {
  const value = config.model_config_json.model;
  return typeof value === "string" && value ? value : t("agents.noModelSelected");
}

function formatAgentProvider(config: AgentConfig, t: ReturnType<typeof useTranslation>["t"]) {
  const value = config.model_config_json.provider;
  return typeof value === "string" && value ? readableAgentValue(value, t) : t("agents.providerNotSet");
}

function readableAgentValue(value: string, t: ReturnType<typeof useTranslation>["t"]) {
  const fallback = value.split(/[_-]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
  return t(`agents.valueLabels.${value}`, fallback);
}

function EditAgentDialog({
  agent,
  activeConfig,
  open,
  onOpenChange,
  onSaved,
}: {
  agent: AgentDefinition;
  activeConfig?: AgentConfig;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSaved: () => void;
}) {
  const { t } = useTranslation();
  const [name, setName] = React.useState(agent.name);
  const [systemPrompt, setSystemPrompt] = React.useState(activeConfig?.system_prompt ?? "");
  const [models, setModels] = React.useState<ModelDefinition[]>([]);
  const [selectedModelId, setSelectedModelId] = React.useState("");
  const [availableSkills, setAvailableSkills] = React.useState<SkillDefinition[]>([]);
  const [selectedSkillIds, setSelectedSkillIds] = React.useState<string[]>([]);
  const [skillsLoading, setSkillsLoading] = React.useState(false);
  const [skillsError, setSkillsError] = React.useState<string | null>(null);
  const [memoryScope, setMemoryScope] = React.useState("session");
  const [temperature, setTemperature] = React.useState("0.7");
  const [maxTokens, setMaxTokens] = React.useState("4096");
  const [timeoutSeconds, setTimeoutSeconds] = React.useState("60");
  const [retryAttempts, setRetryAttempts] = React.useState("2");
  const [retryBackoffMs, setRetryBackoffMs] = React.useState("800");
  const [toolCallLimit, setToolCallLimit] = React.useState("8");
  const [contextWindow, setContextWindow] = React.useState("");
  const [outputFormat, setOutputFormat] = React.useState("text");
  const [humanApprovalPolicy, setHumanApprovalPolicy] = React.useState("never");
  const [submitting, setSubmitting] = React.useState(false);

  const currentModel = models.find((model) => model.id === selectedModelId);
  const modelOptions = React.useMemo(() => {
    return models
      .filter((model) => {
        const capabilities = model.capabilities_json ?? [];
        return capabilities.length === 0 || capabilities.includes("chat") || capabilities.includes("reasoning");
      })
      .map((model) => ({
        value: model.id,
        label: `${model.name} - ${model.model_name}`,
      }));
  }, [models]);

  React.useEffect(() => {
    if (!open) return;
    setName(agent.name);
    hydrateFromConfig(activeConfig);
    void listModels().then((items) => {
      setModels(items);
      hydrateModelSelection(items, activeConfig);
    });
    setSkillsLoading(true);
    setSkillsError(null);
    void listSkills()
      .then((skills) => setAvailableSkills(Array.isArray(skills) ? skills : []))
      .catch((err) => {
        setAvailableSkills([]);
        setSkillsError(translateApiError(err));
      })
      .finally(() => setSkillsLoading(false));
  }, [open, agent, activeConfig]);

  function hydrateFromConfig(config?: AgentConfig) {
    const modelConfig = config?.model_config_json ?? {};
    const memoryPolicy = config?.memory_policy_json ?? {};
    const runtimePolicy = config?.runtime_policy_json ?? {};
    const retryPolicy = getRecord(runtimePolicy, "retry_policy") ?? {};

    setSystemPrompt(config?.system_prompt ?? "");
    setSelectedSkillIds((config?.skill_refs_json ?? []).flatMap((item) => {
      const skillId = getString(item, "skill_id");
      return skillId ? [skillId] : [];
    }));
    setMemoryScope(getString(memoryPolicy, "memory_scope") ?? "session");
    setTemperature(getConfigString(modelConfig, "temperature", "0.7"));
    setMaxTokens(getConfigString(modelConfig, "max_tokens", "4096"));
    setTimeoutSeconds(getConfigString(modelConfig, "timeout_seconds", "60"));
    setContextWindow(getConfigString(modelConfig, "context_window", ""));
    setOutputFormat(getString(modelConfig, "output_format") ?? "text");
    setRetryAttempts(getConfigString(retryPolicy, "max_attempts", "2"));
    setRetryBackoffMs(getConfigString(retryPolicy, "backoff_ms", "800"));
    setToolCallLimit(getConfigString(runtimePolicy, "tool_call_limit", "8"));
    setHumanApprovalPolicy(getString(runtimePolicy, "human_approval_policy") ?? "never");
  }

  function hydrateModelSelection(items: ModelDefinition[], config?: AgentConfig) {
    const modelConfig = config?.model_config_json ?? {};
    const modelDefinitionId = getString(modelConfig, "model_id");
    const providerType = getString(modelConfig, "provider");
    const modelName = getString(modelConfig, "model");
    const matchedModel = items.find((model) =>
      model.id === modelDefinitionId || (model.provider_type === providerType && model.model_name === modelName)
    );
    if (matchedModel) {
      setSelectedModelId(matchedModel.id);
      return;
    }
    const firstModel = items.find((model) => {
      const capabilities = model.capabilities_json ?? [];
      return capabilities.length === 0 || capabilities.includes("chat") || capabilities.includes("reasoning");
    });
    setSelectedModelId(firstModel?.id ?? "");
  }

  function toggleSkill(skillId: string) {
    setSelectedSkillIds((current) =>
      current.includes(skillId) ? current.filter((id) => id !== skillId) : [...current, skillId]
    );
  }

  async function submit(event: React.FormEvent) {
    event.preventDefault();
    setSubmitting(true);
    try {
      await updateAgent(agent.id, { name: name.trim() });
      await createAgentConfig({
        agent_id: agent.id,
        role: "assistant",
        system_prompt: systemPrompt,
        model_config_json: {
          model_id: currentModel?.id ?? null,
          provider: currentModel?.provider_type ?? getString(activeConfig?.model_config_json ?? {}, "provider") ?? "openai",
          model: currentModel?.model_name ?? getString(activeConfig?.model_config_json ?? {}, "model") ?? "",
          temperature: parseOptionalFloat(temperature) ?? 0.7,
          max_tokens: parseOptionalInteger(maxTokens) ?? 4096,
          timeout_seconds: parseOptionalInteger(timeoutSeconds) ?? 60,
          context_window: parseOptionalInteger(contextWindow),
          output_format: outputFormat,
        },
        memory_policy_json: {
          memory_scope: memoryScope,
        },
        runtime_policy_json: {
          retry_policy: {
            max_attempts: parseOptionalInteger(retryAttempts) ?? 2,
            backoff_ms: parseOptionalInteger(retryBackoffMs) ?? 800,
          },
          tool_call_limit: parseOptionalInteger(toolCallLimit) ?? 8,
          human_approval_policy: humanApprovalPolicy,
        },
        tool_refs_json: activeConfig?.tool_refs_json ?? [],
        skill_refs_json: selectedSkillIds.map((skillId) => ({ skill_id: skillId })),
      });
      toast.success(t("agents.agentUpdated"));
      onOpenChange(false);
      onSaved();
    } catch {
      toast.error(t("agents.failedToUpdateAgent"));
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange} title={t("agents.editAgent")} className="max-w-5xl">
      <form className="space-y-5" onSubmit={submit}>
        <div className="grid gap-5 lg:grid-cols-2">
          <section className="space-y-4">
            <div className="rounded-lg border border-border bg-muted/15 p-4">
              <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">{t("agents.basicAgent")}</p>
              <div className="mt-4 space-y-4">
                <Field label={t("common.name")} required>
                  <Input required value={name} onChange={(event) => setName(event.target.value)} placeholder={t("agents.namePlaceholder")} />
                </Field>
                <Field label={t("agents.systemPrompt")}>
                  <Textarea value={systemPrompt} onChange={(event) => setSystemPrompt(event.target.value)} placeholder={t("agents.systemPromptPlaceholder")} rows={8} />
                </Field>
              </div>
            </div>

            <div className="rounded-lg border border-border bg-muted/10 p-4">
              <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">{t("agents.skills")}</p>
              <div className="mt-4">
                {skillsLoading ? (
                  <div className="rounded-md border border-dashed border-border bg-muted/20 p-3 text-sm text-muted-foreground">
                    {t("agents.loadingSkills")}
                  </div>
                ) : skillsError ? (
                  <div className="rounded-md border border-dashed border-red-500/30 bg-red-500/5 p-3 text-sm text-red-500">
                    {skillsError}
                  </div>
                ) : availableSkills.length > 0 ? (
                  <div className="flex max-h-44 flex-wrap gap-2 overflow-auto pr-1">
                    {availableSkills.map((skill) => (
                      <button
                        key={skill.id}
                        type="button"
                        onClick={() => toggleSkill(skill.id)}
                        className={`flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm transition ${
                          selectedSkillIds.includes(skill.id)
                            ? "border-primary bg-primary/15 text-primary"
                            : "border-border bg-muted/30 text-muted-foreground hover:bg-muted/60"
                        }`}
                      >
                        <Sparkles className="h-3 w-3" />
                        {skill.name}
                      </button>
                    ))}
                  </div>
                ) : (
                  <div className="rounded-md border border-dashed border-border bg-muted/20 p-3 text-sm text-muted-foreground">
                    {t("agents.noSkillsYet")}
                  </div>
                )}
              </div>
            </div>
          </section>

          <aside className="space-y-4 rounded-lg border border-border bg-surface p-4 lg:sticky lg:top-24 lg:max-h-[calc(100dvh-12rem)] lg:overflow-auto">
            <div>
              <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">{t("agents.modelAndMemory")}</p>
              <p className="mt-1 text-sm text-muted-foreground">{t("agents.modelAndMemoryHint")}</p>
            </div>

            <div className="space-y-4">
              <Field label={t("agents.model")}>
                <Select value={selectedModelId} onChange={(event) => setSelectedModelId(event.target.value)} options={modelOptions} />
              </Field>
              <div className="grid gap-3 sm:grid-cols-2">
                <Field label={t("agents.temperature")}>
                  <Input value={temperature} onChange={(event) => setTemperature(event.target.value)} inputMode="decimal" />
                </Field>
                <Field label={t("agents.maxTokens")}>
                  <Input value={maxTokens} onChange={(event) => setMaxTokens(event.target.value)} inputMode="numeric" />
                </Field>
                <Field label={t("agents.timeoutSeconds")}>
                  <Input value={timeoutSeconds} onChange={(event) => setTimeoutSeconds(event.target.value)} inputMode="numeric" />
                </Field>
                <Field label={t("agents.contextWindow")}>
                  <Input value={contextWindow} onChange={(event) => setContextWindow(event.target.value)} inputMode="numeric" placeholder={t("agents.auto")} />
                </Field>
              </div>
            </div>

            <div className="h-px bg-border" />

            <div className="space-y-4">
              <Field label={t("agents.memoryScope")}>
                <Select
                  value={memoryScope}
                  onChange={(event) => setMemoryScope(event.target.value)}
                  options={[
                    { value: "session", label: t("agents.memoryScopeSession") },
                    { value: "persistent", label: t("agents.memoryScopePersistent") },
                  ]}
                />
              </Field>
            </div>
          </aside>
        </div>

        <div className="rounded-lg border border-border bg-muted/10 p-4">
          <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">{t("agents.executionPolicy")}</p>
          <div className="mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-5">
            <Field label={t("agents.retryAttempts")}>
              <Input value={retryAttempts} onChange={(event) => setRetryAttempts(event.target.value)} inputMode="numeric" />
            </Field>
            <Field label={t("agents.retryBackoffMs")}>
              <Input value={retryBackoffMs} onChange={(event) => setRetryBackoffMs(event.target.value)} inputMode="numeric" />
            </Field>
            <Field label={t("agents.toolCallLimit")}>
              <Input value={toolCallLimit} onChange={(event) => setToolCallLimit(event.target.value)} inputMode="numeric" />
            </Field>
            <Field label={t("agents.outputFormat")}>
              <Select
                value={outputFormat}
                onChange={(event) => setOutputFormat(event.target.value)}
                options={[
                  { value: "text", label: t("agents.outputText") },
                  { value: "json", label: t("common.format.json") },
                  { value: "markdown", label: t("common.format.markdown") },
                ]}
              />
            </Field>
            <Field label={t("agents.humanApproval")}>
              <Select
                value={humanApprovalPolicy}
                onChange={(event) => setHumanApprovalPolicy(event.target.value)}
                options={[
                  { value: "never", label: t("agents.approvalNever") },
                  { value: "sensitive_actions", label: t("agents.approvalSensitiveActions") },
                  { value: "before_final", label: t("agents.approvalBeforeFinal") },
                  { value: "always", label: t("agents.approvalAlways") },
                ]}
              />
            </Field>
          </div>
        </div>

        <div className="flex justify-end gap-2 border-t border-border pt-4">
          <Button type="button" variant="ghost" onClick={() => onOpenChange(false)}>
            {t("common.cancel")}
          </Button>
          <Button disabled={submitting || !name.trim()}>{submitting ? t("common.saving") : t("common.save")}</Button>
        </div>
      </form>
    </Dialog>
  );
}

function Field({ label, children, required }: { label: string; children: React.ReactNode; required?: boolean }) {
  return (
    <label className="block space-y-2 text-sm">
      <span className="text-muted-foreground">
        {label}
        {required && <span className="text-red-500 ml-0.5">*</span>}
      </span>
      {children}
    </label>
  );
}

function parseOptionalInteger(value: string) {
  if (!value.trim()) return null;
  const parsed = Number.parseInt(value, 10);
  return Number.isFinite(parsed) ? parsed : null;
}

function parseOptionalFloat(value: string) {
  if (!value.trim()) return null;
  const parsed = Number.parseFloat(value);
  return Number.isFinite(parsed) ? parsed : null;
}

function getConfigString(value: JSONObject, key: string, fallback: string) {
  const item = value[key];
  if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") return String(item);
  return fallback;
}

function getString(value: JSONObject, key: string) {
  const item = value[key];
  return typeof item === "string" ? item : undefined;
}

function getRecord(value: JSONObject, key: string): JSONObject | undefined {
  const item = value[key];
  return item && typeof item === "object" && !Array.isArray(item) ? item as JSONObject : undefined;
}

