import { Link, Navigate, createFileRoute } from "@tanstack/react-router"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { CaretRightIcon } from "@phosphor-icons/react"
import { useEffect, useMemo, useState } from "react"

import type {
  DatadogConnectBody,
  LangSmithConnectBody,
  ModelOption,
  PRTraceResolutionResult,
  TeamSettings,
  UserMapping,
} from "@/lib/api"
import { AppShell, SettingsRow, SettingsSection } from "@/components/AppShell"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import { Skeleton } from "@/components/ui/skeleton"
import { api } from "@/lib/api"
import { RequireLogin } from "@/lib/auth-redirect"
import { useSession } from "@/lib/session"

export const Route = createFileRoute("/admin")({ component: AdminPage })

function AdminPage() {
  const session = useSession()

  const options = useQuery({
    queryKey: ["options"],
    queryFn: api.options,
    enabled: !!session.data?.is_admin,
  })

  if (session.isLoading) {
    return (
      <main className="p-6">
        <Skeleton className="h-64 w-full" />
      </main>
    )
  }
  if (!session.data) return <RequireLogin />
  if (!session.data.is_admin) return <Navigate to="/my-settings" />

  return (
    <AppShell
      user={session.data}
      title="Admin"
      description="Workspace-wide defaults and user mappings."
    >
      <GlobalDefaultsSection models={options.data?.models ?? []} />

      <LLMGatewaySection />

      <TriggerReviewSection />

      <SettingsSection title="Evals">
        <Link
          to="/admin/evals"
          className="flex items-center justify-between gap-6 px-4 py-3 hover:bg-muted/40"
        >
          <div className="flex flex-col gap-0.5">
            <span className="text-xs font-medium text-foreground">
              Reviewer eval
            </span>
            <span className="text-xs text-muted-foreground">
              Run the offline reviewer benchmark and watch its output stream
              live.
            </span>
          </div>
          <CaretRightIcon className="size-3.5 shrink-0 text-muted-foreground" />
        </Link>
      </SettingsSection>

      <ObservabilityCredentialsSection />

      <PRTraceResolutionSection />

      <UserMappingsSection enabled={!!session.data.is_admin} />
    </AppShell>
  )
}

const PR_URL_RE = /^https:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)/

function TriggerReviewSection() {
  const [url, setUrl] = useState("")
  const [error, setError] = useState<string | null>(null)
  const [message, setMessage] = useState<string | null>(null)
  const [trace, setTrace] = useState<PRTraceResolutionResult | null>(null)

  const parsed = useMemo(() => {
    const match = PR_URL_RE.exec(url.trim())
    if (!match) return null
    const [, owner, repo, number] = match
    if (!owner || !repo || !number) return null
    return { owner, repo, number: Number(number) }
  }, [url])

  const trigger = useMutation({
    mutationFn: () => {
      if (!parsed) throw new Error("invalid PR URL")
      return api.reReview(parsed.owner, parsed.repo, parsed.number)
    },
    onSuccess: (result) => {
      setError(null)
      setMessage(
        result.queued
          ? "Review queued — a run is already in progress on this PR."
          : "Review started."
      )
    },
    onError: (e: Error) => {
      setMessage(null)
      setError(e.message)
    },
  })

  const resolveTrace = useMutation({
    mutationFn: () => {
      if (!parsed) throw new Error("invalid PR URL")
      return api.resolveTrace(parsed.owner, parsed.repo, parsed.number)
    },
    onSuccess: (result) => {
      setError(null)
      setMessage(null)
      setTrace(result)
    },
    onError: (e: Error) => {
      setTrace(null)
      setError(e.message)
    },
  })

  return (
    <SettingsSection
      title="Trigger a review"
      description="Manually start an Open SWE Review run on a pull request, or dry-run author trace resolution for it. The repository must be enabled for review."
    >
      <div className="flex flex-col gap-2 p-4">
        <div className="flex items-center gap-2">
          <Input
            className="flex-1"
            placeholder="https://github.com/owner/repo/pull/123"
            value={url}
            onChange={(e) => {
              setUrl(e.target.value)
              setMessage(null)
              setError(null)
              setTrace(null)
            }}
          />
          <Button
            size="sm"
            variant="outline"
            onClick={() => resolveTrace.mutate()}
            disabled={!parsed || resolveTrace.isPending}
          >
            {resolveTrace.isPending ? "Resolving…" : "Resolve trace"}
          </Button>
          <Button
            size="sm"
            onClick={() => trigger.mutate()}
            disabled={!parsed || trigger.isPending}
          >
            {trigger.isPending ? "Starting…" : "Start review"}
          </Button>
        </div>
        {url.trim() && !parsed && (
          <p className="text-xs text-muted-foreground">
            Enter a full PR URL like https://github.com/owner/repo/pull/123
          </p>
        )}
        {message && parsed && (
          <p className="text-xs text-muted-foreground">
            {message}{" "}
            <Link
              to="/agents/reviews/$owner/$repo/$number"
              params={{
                owner: parsed.owner,
                repo: parsed.repo,
                number: String(parsed.number),
              }}
              className="underline hover:text-foreground"
            >
              View review
            </Link>
          </p>
        )}
        {trace &&
          (trace.resolved ? (
            <p className="text-xs text-muted-foreground">
              Resolved thread{" "}
              <code className="font-mono">{trace.thread_id}</code> · confidence{" "}
              {trace.confidence?.toFixed(2)} · {trace.evidence.join(", ")} ·{" "}
              {trace.run_count} run{trace.run_count === 1 ? "" : "s"}
              {trace.trace_url && (
                <>
                  {" · "}
                  <a
                    href={trace.trace_url}
                    target="_blank"
                    rel="noreferrer"
                    className="underline hover:text-foreground"
                  >
                    open trace
                  </a>
                </>
              )}
            </p>
          ) : (
            <p className="text-xs text-muted-foreground">
              No trace resolved — {trace.detail}
              {trace.project ? ` (project: ${trace.project})` : ""}
            </p>
          ))}
        {error && <p className="text-xs text-destructive">{error}</p>}
      </div>
    </SettingsSection>
  )
}

const PAGE_SIZE = 20

function UserMappingsSection({ enabled }: { enabled: boolean }) {
  const [error, setError] = useState<string | null>(null)
  const [page, setPage] = useState(1)

  const mappings = useQuery({
    queryKey: ["adminUserMappings", page],
    queryFn: () => api.adminListUserMappings(page, PAGE_SIZE),
    enabled,
  })

  const total = mappings.data?.total ?? 0
  const pageCount = Math.max(1, Math.ceil(total / PAGE_SIZE))

  useEffect(() => {
    if (!mappings.isFetching && page > pageCount) {
      setPage(pageCount)
    }
  }, [mappings.isFetching, page, pageCount])

  const remove = useMutation({
    mutationFn: (gh: string) => api.adminDeleteUserMapping(gh),
    onSuccess: () => void mappings.refetch(),
    onError: (e: Error) => setError(e.message),
  })

  const items = mappings.data?.items ?? []

  return (
    <SettingsSection
      title="User mappings"
      description="Mappings are created when users connect Slack from settings. Admins can remove stale mappings here."
    >
      <div className="flex flex-col gap-3 p-4">
        {error && <span className="text-xs text-destructive">{error}</span>}

        <div className="flex flex-col gap-0.5">
          {mappings.isLoading ? (
            <Skeleton className="h-32" />
          ) : !items.length ? (
            <p className="text-xs text-muted-foreground">No mappings yet.</p>
          ) : (
            items.map((m: UserMapping) => (
              <div
                key={m.github_login}
                className="flex items-center justify-between gap-2 border-b border-border py-1.5 text-xs last:border-b-0"
              >
                <div className="flex min-w-0 flex-col">
                  <span className="truncate font-medium">{m.github_login}</span>
                  <span className="truncate text-xs text-muted-foreground">
                    {m.work_email}
                    {m.slack_user_id ? ` · ${m.slack_user_id}` : ""}
                    {m.source ? ` · ${m.source}` : ""}
                  </span>
                </div>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => remove.mutate(m.github_login)}
                  disabled={remove.isPending}
                >
                  Remove
                </Button>
              </div>
            ))
          )}
        </div>

        {total > PAGE_SIZE && (
          <div className="flex items-center justify-between pt-1 text-xs text-muted-foreground">
            <span>
              {total} mapping{total === 1 ? "" : "s"} · page {page} of{" "}
              {pageCount}
            </span>
            <div className="flex items-center gap-2">
              <Button
                variant="outline"
                size="sm"
                onClick={() => setPage((p) => Math.max(1, p - 1))}
                disabled={page <= 1 || mappings.isFetching}
              >
                Previous
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={() => setPage((p) => Math.min(pageCount, p + 1))}
                disabled={page >= pageCount || mappings.isFetching}
              >
                Next
              </Button>
            </div>
          </div>
        )}
      </div>
    </SettingsSection>
  )
}

function ObservabilityCredentialsSection() {
  const qc = useQueryClient()
  const creds = useQuery({
    queryKey: ["teamCredentials"],
    queryFn: api.getTeamCredentials,
  })
  const [error, setError] = useState<string | null>(null)

  const [ddSite, setDdSite] = useState("datadoghq.com")
  const [ddApiKey, setDdApiKey] = useState("")
  const [ddAppKey, setDdAppKey] = useState("")
  const [lsApiKey, setLsApiKey] = useState("")
  const [lsEndpoint, setLsEndpoint] = useState("")

  const onError = (e: Error) => setError(e.message)
  const onSuccess = (
    saved: Awaited<ReturnType<typeof api.getTeamCredentials>>
  ) => {
    qc.setQueryData(["teamCredentials"], saved)
    setError(null)
  }

  const connectDd = useMutation({
    mutationFn: (body: DatadogConnectBody) => api.connectDatadog(body),
    onSuccess: (saved) => {
      onSuccess(saved)
      setDdApiKey("")
      setDdAppKey("")
    },
    onError,
  })
  const disconnectDd = useMutation({
    mutationFn: () => api.disconnectDatadog(),
    onSuccess,
    onError,
  })
  const connectLs = useMutation({
    mutationFn: (body: LangSmithConnectBody) => api.connectLangSmith(body),
    onSuccess: (saved) => {
      onSuccess(saved)
      setLsApiKey("")
    },
    onError,
  })
  const disconnectLs = useMutation({
    mutationFn: () => api.disconnectLangSmith(),
    onSuccess,
    onError,
  })

  const datadog = creds.data?.datadog
  const langsmith = creds.data?.langsmith
  const busy = creds.isLoading

  return (
    <SettingsSection
      title="Observability credentials"
      description="Team-wide Datadog and LangSmith credentials. Stored encrypted server-side and never exposed to the sandbox. Connecting enables read-only observability tools for agent runs."
    >
      <div className="divide-y divide-border">
        <SettingsRow
          label="Datadog"
          description={
            datadog?.connected
              ? `Connected · ${datadog.site ?? ""} · key ••••${datadog.api_key_last4 ?? ""}`
              : "Connect Datadog to enable read-only metrics, logs, traces, and monitor tools."
          }
          control={
            datadog?.connected ? (
              <Button
                variant="outline"
                size="sm"
                onClick={() => disconnectDd.mutate()}
                disabled={disconnectDd.isPending}
              >
                Disconnect
              </Button>
            ) : (
              <div className="flex flex-col items-end gap-2">
                <Input
                  className="w-56"
                  placeholder="datadoghq.com"
                  value={ddSite}
                  onChange={(e) => setDdSite(e.target.value)}
                  disabled={busy}
                />
                <Input
                  className="w-56"
                  placeholder="API key"
                  type="password"
                  value={ddApiKey}
                  onChange={(e) => setDdApiKey(e.target.value)}
                  disabled={busy}
                />
                <Input
                  className="w-56"
                  placeholder="Application key"
                  type="password"
                  value={ddAppKey}
                  onChange={(e) => setDdAppKey(e.target.value)}
                  disabled={busy}
                />
                <Button
                  size="sm"
                  onClick={() =>
                    connectDd.mutate({
                      site: ddSite.trim(),
                      api_key: ddApiKey.trim(),
                      app_key: ddAppKey.trim(),
                    })
                  }
                  disabled={
                    connectDd.isPending ||
                    !ddSite.trim() ||
                    !ddApiKey.trim() ||
                    !ddAppKey.trim()
                  }
                >
                  Connect
                </Button>
              </div>
            )
          }
        />
        <SettingsRow
          label="LangSmith"
          description={
            langsmith?.connected
              ? `Connected · key ••••${langsmith.api_key_last4 ?? ""}${langsmith.endpoint ? ` · ${langsmith.endpoint}` : ""}`
              : "Connect LangSmith to enable read-only trace and run lookup tools."
          }
          control={
            langsmith?.connected ? (
              <Button
                variant="outline"
                size="sm"
                onClick={() => disconnectLs.mutate()}
                disabled={disconnectLs.isPending}
              >
                Disconnect
              </Button>
            ) : (
              <div className="flex flex-col items-end gap-2">
                <Input
                  className="w-56"
                  placeholder="API key"
                  type="password"
                  value={lsApiKey}
                  onChange={(e) => setLsApiKey(e.target.value)}
                  disabled={busy}
                />
                <Input
                  className="w-56"
                  placeholder="Endpoint (optional)"
                  value={lsEndpoint}
                  onChange={(e) => setLsEndpoint(e.target.value)}
                  disabled={busy}
                />
                <Button
                  size="sm"
                  onClick={() =>
                    connectLs.mutate({
                      api_key: lsApiKey.trim(),
                      endpoint: lsEndpoint.trim() || null,
                    })
                  }
                  disabled={connectLs.isPending || !lsApiKey.trim()}
                >
                  Connect
                </Button>
              </div>
            )
          }
        />
      </div>
      {error && <p className="px-4 pb-3 text-xs text-destructive">{error}</p>}
    </SettingsSection>
  )
}

function PRTraceResolutionSection() {
  const qc = useQueryClient()
  const settings = useQuery({
    queryKey: ["teamSettings"],
    queryFn: api.getTeamSettings,
  })
  const [projectDraft, setProjectDraft] = useState("")
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setProjectDraft(settings.data?.review_tracing_project ?? "")
  }, [settings.data?.review_tracing_project])

  const save = useMutation({
    mutationFn: (body: TeamSettings) => api.saveTeamSettings(body),
    onSuccess: (saved) => {
      qc.setQueryData(["teamSettings"], saved)
      setError(null)
    },
    onError: (e: Error) => setError(e.message),
  })

  const savedProject = settings.data?.review_tracing_project ?? ""
  const projectDirty = projectDraft.trim() !== savedProject

  const saveProject = () => {
    if (!settings.data || !projectDirty) return
    save.mutate({
      ...settings.data,
      review_tracing_project: projectDraft.trim() || null,
    })
  }

  return (
    <SettingsSection
      title="PR Trace Resolution"
      description="Allow Open SWE Review to resolve PRs to author coding-agent traces in a configured LangSmith project. Requires connected LangSmith credentials."
    >
      <div className="divide-y divide-border">
        <SettingsRow
          label="Tracing project"
          description="LangSmith project name or ID to search for author traces. Leave blank to disable trace resolution."
          control={
            <div className="flex items-center gap-2">
              <Input
                className="w-64"
                placeholder="Project name or ID"
                value={projectDraft}
                onChange={(e) => setProjectDraft(e.target.value)}
                onBlur={saveProject}
                disabled={!settings.data || save.isPending}
              />
              <Button
                size="sm"
                variant="outline"
                onClick={saveProject}
                disabled={!settings.data || !projectDirty || save.isPending}
              >
                Save
              </Button>
            </div>
          }
        />
      </div>
      {error && <p className="px-4 pb-3 text-xs text-destructive">{error}</p>}
    </SettingsSection>
  )
}

type GatewayMode = "inherit" | "enabled" | "disabled"

function gatewayMode(value: boolean | null | undefined): GatewayMode {
  if (value === true) return "enabled"
  if (value === false) return "disabled"
  return "inherit"
}

function gatewayModeValue(mode: GatewayMode): boolean | null {
  if (mode === "enabled") return true
  if (mode === "disabled") return false
  return null
}

function LLMGatewaySection() {
  const qc = useQueryClient()
  const settings = useQuery({
    queryKey: ["teamSettings"],
    queryFn: api.getTeamSettings,
  })
  const [error, setError] = useState<string | null>(null)

  const save = useMutation({
    mutationFn: (body: TeamSettings) => api.saveTeamSettings(body),
    onSuccess: (saved) => {
      qc.setQueryData(["teamSettings"], saved)
      setError(null)
    },
    onError: (e: Error) => setError(e.message),
  })

  const mode = gatewayMode(settings.data?.gateway_enabled)

  return (
    <SettingsSection
      title="LLM Gateway"
      description="Route agent and reviewer LLM calls through the LangSmith LLM Gateway. It authenticates with the workspace LangSmith API key and resolves provider keys from Provider Secrets, so no provider keys are needed at runtime. Requires the gateway (private beta) enabled for your organization."
    >
      <div className="divide-y divide-border">
        <SettingsRow
          label="Route through the gateway"
          description="Inherit uses the LANGSMITH_GATEWAY_ENABLED deployment default. OpenAI, Anthropic, Fireworks, and Google Gemini are routed; other providers call the provider directly."
          control={
            <Select
              value={mode}
              onValueChange={(next) =>
                settings.data &&
                save.mutate({
                  ...settings.data,
                  gateway_enabled: gatewayModeValue(next as GatewayMode),
                })
              }
              disabled={!settings.data || save.isPending}
            >
              <SelectTrigger className="w-48">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="inherit">Inherit deployment default</SelectItem>
                <SelectItem value="enabled">Enabled</SelectItem>
                <SelectItem value="disabled">Disabled</SelectItem>
              </SelectContent>
            </Select>
          }
        />
      </div>
      {error && <p className="px-4 pb-3 text-xs text-destructive">{error}</p>}
    </SettingsSection>
  )
}

function GlobalDefaultsSection({ models }: { models: Array<ModelOption> }) {
  const qc = useQueryClient()
  const settings = useQuery({
    queryKey: ["teamSettings"],
    queryFn: api.getTeamSettings,
  })
  const [error, setError] = useState<string | null>(null)
  const [defaultRepoDraft, setDefaultRepoDraft] = useState("")

  useEffect(() => {
    setDefaultRepoDraft(settings.data?.default_repo ?? "")
  }, [settings.data?.default_repo])

  const save = useMutation({
    mutationFn: (body: TeamSettings) => api.saveTeamSettings(body),
    onSuccess: (saved) => {
      qc.setQueryData(["teamSettings"], saved)
      setError(null)
    },
    onError: (e: Error) => setError(e.message),
  })

  return (
    <SettingsSection
      title="Global defaults"
      description="Workspace-wide model defaults. Per-user Cloud Agent selections override the agent defaults."
    >
      <div className="divide-y divide-border">
        <RolePicker
          label="Open SWE Agent"
          description="Model used for code-writing runs triggered from Slack, Linear, GitHub, and the Open SWE Agent."
          models={models}
          model={settings.data?.default_agent_model ?? null}
          effort={settings.data?.default_agent_reasoning_effort ?? null}
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_agent_model: model,
              default_agent_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
        <RolePicker
          label="Open SWE Agent subagents"
          description="Model used by delegated main-agent tasks."
          models={models}
          model={settings.data?.default_agent_subagent_model ?? null}
          effort={
            settings.data?.default_agent_subagent_reasoning_effort ?? null
          }
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_agent_subagent_model: model,
              default_agent_subagent_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
        <SettingsRow
          label="Default Repository"
          description="Global fallback used when a run has no explicit repo and the user has no profile default. Use owner/repo."
          control={
            <Input
              className="w-56"
              placeholder="owner/repo"
              value={defaultRepoDraft}
              onChange={(e) => setDefaultRepoDraft(e.target.value)}
              onBlur={() =>
                settings.data &&
                save.mutate({
                  ...settings.data,
                  default_repo: defaultRepoDraft.trim() || null,
                })
              }
              disabled={!settings.data || save.isPending}
            />
          }
        />
        <RolePicker
          label="Open SWE Reviewer"
          description="Model used for PR review runs."
          models={models}
          model={settings.data?.default_reviewer_model ?? null}
          effort={settings.data?.default_reviewer_reasoning_effort ?? null}
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_reviewer_model: model,
              default_reviewer_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
        <RolePicker
          label="Open SWE Reviewer subagents"
          description="Model used by delegated reviewer tasks."
          models={models}
          model={settings.data?.default_reviewer_subagent_model ?? null}
          effort={
            settings.data?.default_reviewer_subagent_reasoning_effort ?? null
          }
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_reviewer_subagent_model: model,
              default_reviewer_subagent_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
        <RolePicker
          label="Open SWE Review Diff Grouping"
          description="Model used for the review's 'AI sorted' view that groups changed files into a logical walkthrough. Inherits the Reviewer subagent default when unset."
          models={models}
          model={settings.data?.default_grouping_model ?? null}
          effort={settings.data?.default_grouping_reasoning_effort ?? null}
          inheritLabel="Reviewer subagent default"
          onInherit={() =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_grouping_model: null,
              default_grouping_reasoning_effort: null,
            })
          }
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_grouping_model: model,
              default_grouping_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
        <RolePicker
          label="Open SWE Review Chat"
          description="Model used by the 'chat with this PR' assistant on the review page. Inherits the Agent default when unset."
          models={models}
          model={settings.data?.default_chat_model ?? null}
          effort={settings.data?.default_chat_reasoning_effort ?? null}
          inheritLabel="Agent default"
          onInherit={() =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_chat_model: null,
              default_chat_reasoning_effort: null,
            })
          }
          onChange={(model, effort) =>
            settings.data &&
            save.mutate({
              ...settings.data,
              default_chat_model: model,
              default_chat_reasoning_effort: effort,
            })
          }
          disabled={!settings.data || save.isPending}
        />
      </div>
      {error && <p className="px-4 pb-3 text-xs text-destructive">{error}</p>}
    </SettingsSection>
  )
}

interface RolePickerProps {
  label: string
  description: string
  models: Array<ModelOption>
  model: string | null
  effort: string | null
  onChange: (model: string, effort: string) => void
  disabled: boolean
  /**
   * When set, the model dropdown gains a leading "inherit" option with this
   * label. Selecting it calls {@link onInherit} (clearing the override); an
   * unset `model` renders as this option.
   */
  inheritLabel?: string
  onInherit?: () => void
}

const INHERIT_VALUE = "__inherit__"

function RolePicker({
  label,
  description,
  models,
  model,
  effort,
  onChange,
  disabled,
  inheritLabel,
  onInherit,
}: RolePickerProps) {
  const inheritFallback = inheritLabel ? INHERIT_VALUE : ""
  const [localModel, setLocalModel] = useState<string>(model ?? inheritFallback)
  const [localEffort, setLocalEffort] = useState<string>(effort ?? "")

  useEffect(() => {
    setLocalModel(model ?? inheritFallback)
    setLocalEffort(effort ?? "")
  }, [model, effort, inheritFallback])

  const isInherit = localModel === INHERIT_VALUE
  const selectedModel = models.find((m) => m.id === localModel)
  const availableEfforts = selectedModel?.efforts ?? []

  const handleModelChange = (value: string | null) => {
    if (!value) return
    if (value === INHERIT_VALUE) {
      setLocalModel(INHERIT_VALUE)
      setLocalEffort("")
      onInherit?.()
      return
    }
    const nextModel = models.find((m) => m.id === value)
    if (!nextModel) return
    const nextEffort = nextModel.efforts.includes(localEffort)
      ? localEffort
      : nextModel.default_effort
    setLocalModel(value)
    setLocalEffort(nextEffort)
    onChange(value, nextEffort)
  }

  const handleEffortChange = (value: string | null) => {
    if (!value || !localModel || isInherit) return
    setLocalEffort(value)
    onChange(localModel, value)
  }

  return (
    <SettingsRow
      label={label}
      description={description}
      control={
        <div className="flex items-center gap-2">
          <Select
            value={localModel}
            onValueChange={handleModelChange}
            disabled={disabled}
          >
            <SelectTrigger className="w-40">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {inheritLabel && (
                <SelectItem value={INHERIT_VALUE}>{inheritLabel}</SelectItem>
              )}
              {models.map((m) => (
                <SelectItem key={m.id} value={m.id}>
                  {m.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <Select
            value={localEffort}
            onValueChange={handleEffortChange}
            disabled={disabled || !localModel || isInherit}
          >
            <SelectTrigger className="w-28">
              <SelectValue placeholder="effort" />
            </SelectTrigger>
            <SelectContent>
              {availableEfforts.map((e) => (
                <SelectItem key={e} value={e}>
                  {e}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      }
    />
  )
}
