import { useEffect, useState } from 'react'
import { Alert } from '@/components/ui/Alert'
import { Button } from '@/components/ui/Button'
import { Select } from '@/components/ui/Select'
import { TextField } from '@/components/ui/TextField'
import { toast } from '@/components/ui/toast'
import { errorMessage } from '@/lib/api'
import {
  conflictSettings,
  useSettings,
  useUpdateSettings,
  type EffectiveAgent,
  type InstanceSettings,
} from '@/lib/settings'
import { usePageTitle } from '@/lib/usePageTitle'

// agentEnabled is a tri-state on the wire (null = inherit env, true, false); the
// form models it as three named choices so "inherit" is a deliberate pick, not
// an empty control.
type EnabledChoice = 'inherit' | 'on' | 'off'
const toChoice = (v: boolean | null): EnabledChoice => (v === null ? 'inherit' : v ? 'on' : 'off')
const fromChoice = (c: EnabledChoice): boolean | null => (c === 'inherit' ? null : c === 'on')

/** Admin-only instance settings (#79). The one that matters today is the agent
 *  model; the API key stays in the environment and is only ever reported as
 *  present/absent, never shown or edited. */
export function SettingsPage() {
  usePageTitle('Settings')
  const settings = useSettings()
  const update = useUpdateSettings()

  if (settings.isPending) {
    return <p className="text-sm text-muted">Loading settings…</p>
  }
  if (settings.isError) {
    return <Alert>{errorMessage(settings.error, "Couldn't load settings.")}</Alert>
  }
  return <SettingsForm data={settings.data} update={update} />
}

function SettingsForm({
  data,
  update,
}: {
  data: { settings: InstanceSettings; effective: EffectiveAgent }
  update: ReturnType<typeof useUpdateSettings>
}) {
  const [model, setModel] = useState(data.settings.agentModel)
  const [enabled, setEnabled] = useState<EnabledChoice>(toChoice(data.settings.agentEnabled))
  const [version, setVersion] = useState(data.settings.version)
  const [error, setError] = useState<string | null>(null)

  // Rebase the form when the query cache updates (e.g. a successful save writes
  // the new row back), so the version we submit is never stale.
  useEffect(() => {
    setVersion(data.settings.version)
  }, [data.settings.version])

  const eff = data.effective

  const save = () => {
    setError(null)
    update.mutate(
      { agentModel: model.trim(), agentEnabled: fromChoice(enabled), version },
      {
        onSuccess: () => toast.info('Settings saved.'),
        onError: (err) => {
          const current = conflictSettings(err)
          if (current) {
            // Someone else saved first. Adopt their row so the next attempt is
            // clean, and say so rather than silently discarding this edit.
            setModel(current.agentModel)
            setEnabled(toChoice(current.agentEnabled))
            setVersion(current.version)
            setError('Someone else changed these settings just now — reloaded their version. Re-apply your change if you still want it.')
            return
          }
          setError(errorMessage(err, "Couldn't save settings."))
        },
      },
    )
  }

  return (
    <div className="flex max-w-2xl flex-col gap-6">
      <div>
        <h1 className="text-xl font-semibold text-fg">Settings</h1>
        <p className="mt-1 text-sm text-muted">
          Instance-wide, admin-only. Changes take effect immediately — no restart.
        </p>
      </div>

      <section className="flex flex-col gap-4 rounded-lg border border-border p-4">
        <div>
          <h2 className="text-sm font-semibold text-fg">Garden assistant</h2>
          <p className="mt-1 text-xs text-muted">
            The model runs against your Ollama Cloud key, which is set in the environment and never
            shown here.
          </p>
        </div>

        <AgentStatus eff={eff} />

        <TextField
          label="Model"
          name="agentModel"
          placeholder={eff.model || 'ollama-cloud/glm-5.2:cloud'}
          value={model}
          onChange={(e) => setModel(e.target.value)}
          hint={
            model.trim() === ''
              ? `Empty — inheriting ${eff.model || 'the built-in default'} from the environment.`
              : 'A majordomo model spec. A comma-separated list is a failover chain.'
          }
        />

        <Select
          label="Enabled"
          name="agentEnabled"
          value={enabled}
          onChange={(e) => setEnabled(e.target.value as EnabledChoice)}
          options={[
            { value: 'inherit', label: 'Inherit from environment' },
            { value: 'on', label: 'On' },
            { value: 'off', label: 'Off' },
          ]}
        />
      </section>

      {error && <Alert>{error}</Alert>}

      <div className="flex justify-end">
        <Button onClick={save} disabled={update.isPending}>
          {update.isPending ? 'Saving…' : 'Save changes'}
        </Button>
      </div>
    </div>
  )
}

// AgentStatus surfaces the gap the capabilities endpoint exists for: enabled +
// a key does not guarantee the assistant is actually running (an unresolvable
// model leaves it down), and that's precisely what an admin needs to see.
function AgentStatus({ eff }: { eff: EffectiveAgent }) {
  const [tone, text] = eff.agentLive
    ? (['ok', `Live on ${eff.model}`] as const)
    : !eff.hasApiKey
      ? (['warn', 'No API key set in the environment — the assistant is off.'] as const)
      : !eff.enabled
        ? (['warn', 'Turned off.'] as const)
        : (['warn', `Configured but not running — check the model (${eff.model}).`] as const)

  return (
    <div className="flex items-center gap-2 text-sm">
      <span
        className={
          'inline-block h-2 w-2 rounded-full ' + (tone === 'ok' ? 'bg-emerald-500' : 'bg-amber-500')
        }
        aria-hidden
      />
      <span className={tone === 'ok' ? 'text-fg' : 'text-muted'}>{text}</span>
    </div>
  )
}
