// Saved LLM configurations: server-side CRUD + one-shot import of any
// localStorage settings the user had before this surface existed.
//
// Lists configurations (own + platform-default), exposes Add/Delete, and
// surfaces published costs from the curated catalog so the operator can
// see at a glance what each config costs per 1M tokens.

import { useCallback, useEffect, useMemo, useState } from "react"
import { Plus, Trash2, Upload } from "lucide-react"
import { useArcadiaClient } from "@crema/arcadia-client"

import { Button } from "~/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "~/components/ui/card"
import { Input } from "~/components/ui/input"
import { Label } from "~/components/ui/label"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "~/components/ui/select"
import {
  createConfiguration,
  deleteConfiguration,
  formatCost,
  getCatalog,
  getUsageSummary,
  listConfigurations,
  type CatalogEntry,
  type LlmConfiguration,
  type LlmConfigurationInput,
  type LlmProvider,
  type LlmUsageSummary,
} from "~/lib/arcadia/llm-configs"

const PROVIDERS: LlmProvider[] = ["openai", "anthropic", "deepseek", "qwen", "lmstudio"]

const LOCAL_SETTINGS_KEY = "crema.llm-providers.settings"

export function LlmConfigurationsPanel() {
  const arcadia = useArcadiaClient()
  const [configs, setConfigs] = useState<LlmConfiguration[]>([])
  const [catalog, setCatalog] = useState<CatalogEntry[]>([])
  const [usage, setUsage] = useState<LlmUsageSummary | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [creating, setCreating] = useState(false)
  const [draft, setDraft] = useState<LlmConfigurationInput>(emptyDraft())

  const refresh = useCallback(async () => {
    setError(null)
    try {
      const [list, cat, sum] = await Promise.all([
        listConfigurations(arcadia),
        getCatalog(arcadia).catch(() => [] as CatalogEntry[]),
        getUsageSummary(arcadia, { days: 30 }).catch(() => null),
      ])
      setConfigs(list)
      setCatalog(cat)
      setUsage(sum)
    } catch (e) {
      setError(e instanceof Error ? e.message : "Failed to load configurations.")
    } finally {
      setLoading(false)
    }
  }, [arcadia])

  useEffect(() => {
    void refresh()
  }, [refresh])

  const modelsForProvider = useMemo(
    () => catalog.filter((c) => c.provider === draft.provider && c.model !== "*"),
    [catalog, draft.provider],
  )

  const onCreate = async () => {
    setError(null)
    try {
      await createConfiguration(arcadia, draft)
      setDraft(emptyDraft())
      setCreating(false)
      await refresh()
    } catch (e) {
      setError(e instanceof Error ? e.message : "Create failed.")
    }
  }

  const onDelete = async (id: string) => {
    setError(null)
    try {
      await deleteConfiguration(arcadia, id)
      await refresh()
    } catch (e) {
      setError(e instanceof Error ? e.message : "Delete failed.")
    }
  }

  const onImportFromLocal = async () => {
    setError(null)
    const raw = typeof window !== "undefined" ? localStorage.getItem(LOCAL_SETTINGS_KEY) : null
    if (!raw) {
      setError("No local settings found to import.")
      return
    }
    try {
      const local = JSON.parse(raw) as {
        providerId?: string
        model?: string
        baseURL?: string
        secretName?: string
      }
      if (!local.providerId || !local.model) {
        setError("Local settings are incomplete (missing provider or model).")
        return
      }
      await createConfiguration(arcadia, {
        name: `Imported (${local.providerId})`,
        provider: local.providerId as LlmProvider,
        model: local.model,
        base_url: local.baseURL || null,
        secret_name: local.secretName || null,
      })
      // Keep the local store as a fallback in case import fails on a later
      // browser; clearing only happens after a successful refresh confirms
      // the row exists server-side.
      localStorage.removeItem(LOCAL_SETTINGS_KEY)
      await refresh()
    } catch (e) {
      setError(e instanceof Error ? e.message : "Import failed.")
    }
  }

  const hasLocalSettings =
    typeof window !== "undefined" && !!localStorage.getItem(LOCAL_SETTINGS_KEY)

  return (
    <Card>
      <CardHeader className="flex flex-row items-start justify-between gap-4">
        <div className="flex-1">
          <CardTitle>Saved configurations</CardTitle>
          <CardDescription>
            Persisted server-side. Each config bundles a provider, model, vault secret,
            and per-1M-token costs (auto-filled from the catalog). Used by the proxy to
            attribute cost on every completion.
          </CardDescription>
        </div>
        {usage ? (
          <div className="flex shrink-0 flex-col items-end rounded-md border bg-muted/40 px-3 py-2 text-right">
            <span className="text-[10px] uppercase tracking-wide text-muted-foreground">
              Spend (30d)
            </span>
            <span className="font-mono text-base font-semibold tabular-nums">
              {formatCost(usage.total_cost_cents ?? 0)}
            </span>
            <span className="text-[10px] text-muted-foreground">
              {(usage.total_requests ?? 0).toLocaleString()} req ·{" "}
              {(usage.total_tokens ?? 0).toLocaleString()} tok
            </span>
          </div>
        ) : null}
        <div className="flex shrink-0 gap-2">
          {hasLocalSettings ? (
            <Button
              variant="outline"
              size="sm"
              onClick={onImportFromLocal}
              data-action="llm-config-import-local"
            >
              <Upload className="size-4" />
              Import local
            </Button>
          ) : null}
          <Button
            size="sm"
            onClick={() => setCreating((v) => !v)}
            data-action="llm-config-add"
          >
            <Plus className="size-4" />
            Add
          </Button>
        </div>
      </CardHeader>
      <CardContent className="flex flex-col gap-3">
        {error ? (
          <p className="text-sm text-destructive" role="alert">
            {error}
          </p>
        ) : null}

        {creating ? (
          <div className="grid gap-3 rounded-md border bg-muted/30 p-3 sm:grid-cols-2">
            <Field label="Name">
              <Input
                value={draft.name}
                onChange={(e) => setDraft({ ...draft, name: e.target.value })}
                placeholder="Production GPT-4o-mini"
              />
            </Field>
            <Field label="Provider">
              <Select
                value={draft.provider}
                onValueChange={(v) =>
                  setDraft({ ...draft, provider: v as LlmProvider, model: "" })
                }
              >
                <SelectTrigger>
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {PROVIDERS.map((p) => (
                    <SelectItem key={p} value={p}>
                      {p}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </Field>
            <Field label="Model">
              <ModelPicker
                value={draft.model}
                models={modelsForProvider}
                onChange={(model) => setDraft({ ...draft, model })}
              />
            </Field>
            <Field label="Vault secret name (optional)">
              <Input
                value={draft.secret_name ?? ""}
                onChange={(e) => setDraft({ ...draft, secret_name: e.target.value || null })}
                placeholder="llm-openai-key"
              />
            </Field>
            <Field label="Base URL (optional)">
              <Input
                value={draft.base_url ?? ""}
                onChange={(e) => setDraft({ ...draft, base_url: e.target.value || null })}
                placeholder="leave blank for provider default"
              />
            </Field>
            <Field label="Costs">
              <p className="text-xs text-muted-foreground">
                Auto-filled from the curated catalog when you save. Override later if you
                have a negotiated rate.
              </p>
            </Field>
            <div className="sm:col-span-2 flex justify-end gap-2">
              <Button
                variant="ghost"
                onClick={() => {
                  setCreating(false)
                  setDraft(emptyDraft())
                }}
              >
                Cancel
              </Button>
              <Button
                onClick={onCreate}
                disabled={!draft.name || !draft.model}
                data-action="llm-config-save"
              >
                Save
              </Button>
            </div>
          </div>
        ) : null}

        {loading ? (
          <p className="py-4 text-sm text-muted-foreground">Loading…</p>
        ) : configs.length === 0 ? (
          <p className="py-4 text-sm text-muted-foreground">
            No configurations yet. Add one to start tracking cost.
          </p>
        ) : (
          <ul className="divide-y border-y">
            {configs.map((c) => (
              <li key={c.id} className="flex items-center justify-between gap-3 px-1 py-2">
                <div className="flex flex-col gap-0.5">
                  <span className="flex items-center gap-2 text-sm font-medium">
                    {c.name}
                    {c.tenant_id == null ? (
                      <span className="rounded-full bg-muted px-2 py-0.5 text-[10px] uppercase tracking-wide text-muted-foreground">
                        platform
                      </span>
                    ) : null}
                    {!c.enabled ? (
                      <span className="text-[11px] text-muted-foreground">disabled</span>
                    ) : null}
                  </span>
                  <span className="text-xs text-muted-foreground">
                    {c.provider} · <code className="font-mono">{c.model}</code>
                    {c.secret_name ? (
                      <>
                        {" "}
                        · secret <code className="font-mono">{c.secret_name}</code>
                      </>
                    ) : null}
                  </span>
                  <span className="text-[11px] text-muted-foreground">
                    {formatRate(c.input_cost_per_million)}/1M in ·{" "}
                    {formatRate(c.output_cost_per_million)}/1M out
                  </span>
                </div>
                {c.tenant_id != null ? (
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => onDelete(c.id)}
                    data-action={`llm-config-delete-${c.id}`}
                  >
                    <Trash2 className="size-4" />
                  </Button>
                ) : null}
              </li>
            ))}
          </ul>
        )}
      </CardContent>
    </Card>
  )
}

/**
 * Model picker: dropdown of catalog entries for the selected provider, plus
 * a "Custom…" escape hatch that switches to free-text for models the
 * catalog doesn't know about. The custom branch is sticky — once the user
 * types a custom name, switching providers resets to the dropdown.
 */
function ModelPicker({
  value,
  models,
  onChange,
}: {
  value: string
  models: CatalogEntry[]
  onChange: (model: string) => void
}) {
  const known = useMemo(() => new Set(models.map((m) => m.model)), [models])
  const isCustom = value !== "" && !known.has(value)
  const [customMode, setCustomMode] = useState(isCustom)

  // Reset to dropdown if the available models change (e.g. provider switched)
  // and we're not actively in custom mode.
  useEffect(() => {
    if (!isCustom) setCustomMode(false)
  }, [models, isCustom])

  if (customMode) {
    return (
      <div className="flex gap-2">
        <Input
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder="custom-model-id"
          autoFocus
        />
        <Button
          type="button"
          variant="ghost"
          size="sm"
          onClick={() => {
            setCustomMode(false)
            onChange("")
          }}
        >
          Catalog
        </Button>
      </div>
    )
  }

  return (
    <Select
      value={known.has(value) ? value : ""}
      onValueChange={(v) => {
        if (v === "__custom__") {
          setCustomMode(true)
          onChange("")
        } else {
          onChange(v)
        }
      }}
    >
      <SelectTrigger>
        <SelectValue placeholder={models.length ? "Pick a model…" : "No models for this provider"} />
      </SelectTrigger>
      <SelectContent>
        {models.map((m) => (
          <SelectItem key={m.model} value={m.model}>
            <span className="flex items-center justify-between gap-3">
              <span>{m.model}</span>
              <span className="text-[10px] text-muted-foreground">
                ${m.input_cost_per_million.toFixed(2)} / ${m.output_cost_per_million.toFixed(2)} per 1M
              </span>
            </span>
          </SelectItem>
        ))}
        <SelectItem value="__custom__">
          <span className="text-muted-foreground">Custom…</span>
        </SelectItem>
      </SelectContent>
    </Select>
  )
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div className="flex flex-col gap-1">
      <Label className="text-xs">{label}</Label>
      {children}
    </div>
  )
}

function emptyDraft(): LlmConfigurationInput {
  return {
    name: "",
    provider: "openai",
    model: "",
    base_url: null,
    secret_name: null,
  }
}

function formatRate(rate: number | null): string {
  if (rate == null) return "—"
  if (rate === 0) return "free"
  return `$${rate.toFixed(2)}`
}
