<script lang="ts">
  // The desktop's Settings window — a generic shell (section list + content
  // pane) so future settings just add a SECTIONS entry instead of a whole
  // new window/screen. Connection reuses the same config.ts/oidc.ts calls as
  // pages/Config.svelte (the full-page initial setup screen), just without
  // that screen's "first run" framing — this is for changing settings while
  // already inside the desktop.
  import { Input } from '$lib/components/ui/input'
  import { Label } from '$lib/components/ui/label'
  import { Button } from '$lib/components/ui/button'
  import { Separator } from '$lib/components/ui/separator'
  import { Checkbox } from '$lib/components/ui/checkbox'
  import { Slider } from '$lib/components/ui/slider'
  import {
    fetchWithAuth,
    setConfig,
    initConfig,
    getConfig,
    clearConfig,
    type OikosConfig
  } from '$lib/config'
  import { startLogin, logout as oidcLogout, getUser, isOIDCConfigured } from '$lib/oidc'
  import { getTheme, setTheme, THEME_LABELS, type Theme } from '$lib/stores/theme.svelte'
  import {
    getBackground,
    setBackgroundPattern,
    setPatternColor,
    setFillColor,
    setBackgroundOpacity,
    setBackgroundFade,
    setBackgroundScale,
    setBackgroundRotation
  } from '$lib/stores/background.svelte'
  import { PATTERNS, patternCss, type BackgroundPatternId } from '$lib/desktop-patterns'
  import { VERSION } from '$lib/version'
  import { toast } from 'svelte-sonner'
  import PlugIcon from '@lucide/svelte/icons/plug'
  import PaletteIcon from '@lucide/svelte/icons/palette'
  import LockIcon from '@lucide/svelte/icons/lock'
  import LogInIcon from '@lucide/svelte/icons/log-in'
  import ServerIcon from '@lucide/svelte/icons/server'
  import CheckIcon from '@lucide/svelte/icons/check'

  const SECTIONS = [
    { id: 'appearance', label: 'Appearance', icon: PaletteIcon },
    { id: 'connection', label: 'Connection', icon: PlugIcon }
  ] as const
  type SectionId = (typeof SECTIONS)[number]['id']

  let section = $state<SectionId>('appearance')

  const existing = getConfig()
  let apiUrl = $state(existing.apiUrl ?? '')
  let token = $state(existing.token ?? '')
  let saving = $state(false)
  let error = $state('')
  let oidcLoggingIn = $state(false)
  const oidcUser = getUser()
  const oidcConfigured = isOIDCConfigured()

  async function save() {
    error = ''
    if (!token.trim()) {
      error = 'Token is required'
      return
    }
    saving = true
    const prev: OikosConfig = getConfig()
    setConfig({ apiUrl: apiUrl.trim(), token: token.trim() })
    initConfig({ apiUrl: apiUrl.trim(), token: token.trim() })
    try {
      const res = await fetchWithAuth('/api/v1/dashboard/summary')
      if (!res.ok) {
        error = res.status === 401 ? 'Invalid token' : `Server responded ${res.status}`
        setConfig(prev)
        initConfig(prev)
        return
      }
      toast.success('Connection saved')
    } catch {
      error = 'Could not reach server — check the URL'
      setConfig(prev)
      initConfig(prev)
    } finally {
      saving = false
    }
  }

  async function loginWithAuthentik() {
    error = ''
    oidcLoggingIn = true
    setConfig({ apiUrl: apiUrl.trim(), token: '' })
    initConfig({ apiUrl: apiUrl.trim(), token: '' })
    try {
      await startLogin()
    } catch (e: unknown) {
      error = e instanceof Error ? e.message : 'OIDC login failed'
      oidcLoggingIn = false
    }
  }

  // Disconnecting invalidates the token every open window's data depends on
  // — a reload is the simplest way back to a clean state (lands on the
  // full-page Config screen since isConfigured() is now false).
  function forgetConnection() {
    clearConfig()
    oidcLogout()
    location.reload()
  }

  function pickTheme(t: Theme) {
    setTheme(t)
  }

  // Swatch previews render every pattern at a fixed, higher-contrast opacity
  // against a neutral tile so the shape reads clearly in the picker — the
  // live opacity slider (often tuned low, e.g. 0.08, so it reads as texture
  // rather than noise) would make most patterns nearly invisible here.
  const SWATCH_PREVIEW_OPACITY = 0.55

  function swatchStyle(id: BackgroundPatternId, color: string): string {
    const css = patternCss(id, color)
    return css ? `opacity:${SWATCH_PREVIEW_OPACITY};${css}` : ''
  }

  // Remembers the last custom fill color locally so toggling "Custom" off
  // and back on doesn't lose the pick — the store itself only ever holds
  // null (auto/theme) or the active custom color, not a disabled draft.
  let fillDraft = $state(getBackground().fillColor ?? '#ffffff')

  function onFillToggle(checked: boolean) {
    setFillColor(checked ? fillDraft : null)
  }

  function onFillColorInput(e: Event) {
    const val = (e.currentTarget as HTMLInputElement).value
    fillDraft = val
    setFillColor(val)
  }

  // Size/rotation act on the pattern image itself — meaningless with no
  // pattern selected, unlike opacity/fade which also apply to a plain fill
  // color wash (pattern 'none' + a custom fill).
  const noPattern = $derived(getBackground().pattern === 'none')
</script>

<div class="flex h-full min-h-0 flex-col">
  <div class="flex min-h-0 flex-1">
    <nav class="flex w-44 shrink-0 flex-col gap-0.5 border-r bg-muted/20 p-2">
      {#each SECTIONS as s (s.id)}
        <button
          type="button"
          class="flex items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm transition-colors {section ===
          s.id
            ? 'bg-muted font-medium text-foreground'
            : 'text-muted-foreground hover:bg-muted/50 hover:text-foreground'}"
          onclick={() => (section = s.id)}
        >
          <s.icon class="size-4 shrink-0" />
          {s.label}
        </button>
      {/each}
    </nav>

    <div class="min-h-0 flex-1 overflow-y-auto p-6">
      {#if section === 'connection'}
        <div class="mx-auto flex max-w-md flex-col gap-5">
          <div>
            <h2 class="text-sm font-semibold">Connection</h2>
            <p class="mt-0.5 text-xs text-muted-foreground">
              Where the control room talks to your Oikos server.
            </p>
          </div>

          {#if oidcUser}
            <p class="text-xs text-muted-foreground">
              Signed in via Authentik as <span class="font-medium text-foreground">{oidcUser}</span>
            </p>
          {/if}

          <div class="flex flex-col gap-1.5">
            <Label for="settings-server-url" class="text-xs font-medium">Server URL</Label>
            <div class="relative">
              <ServerIcon
                class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground/50"
              />
              <Input
                id="settings-server-url"
                type="url"
                placeholder="https://oikos.hubris.network"
                class="pl-9"
                bind:value={apiUrl}
              />
            </div>
          </div>

          <Button
            type="button"
            variant="secondary"
            disabled={oidcLoggingIn}
            onclick={loginWithAuthentik}
            class="w-full gap-2"
          >
            <LogInIcon class="size-4" />
            {oidcLoggingIn
              ? 'Redirecting…'
              : oidcConfigured
                ? 'Switch account with Authentik'
                : 'Login with Authentik'}
          </Button>

          <div class="flex items-center gap-3">
            <Separator decorative class="flex-1" />
            <span class="text-[10px] font-medium uppercase tracking-widest text-muted-foreground/40"
              >or use</span
            >
            <Separator decorative class="flex-1" />
          </div>

          <form
            class="flex flex-col gap-2.5"
            onsubmit={(e) => {
              e.preventDefault()
              save()
            }}
          >
            <div class="relative">
              <LockIcon
                class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground/50"
              />
              <Input type="password" placeholder="Bearer token" class="pl-9" bind:value={token} />
            </div>
            <Button type="submit" disabled={saving} class="w-full">
              {saving ? 'Saving…' : 'Save'}
            </Button>
          </form>

          {#if error}
            <p class="rounded-lg bg-destructive/10 px-3 py-2 text-center text-sm text-destructive">
              {error}
            </p>
          {/if}

          {#if existing.token || oidcConfigured}
            <div class="flex justify-center pt-1">
              <Button type="button" variant="ghost" size="sm" onclick={forgetConnection}
                >Forget saved connection</Button
              >
            </div>
          {/if}
        </div>
      {:else if section === 'appearance'}
        <div class="mx-auto flex max-w-md flex-col gap-5">
          <div>
            <h2 class="text-sm font-semibold">Appearance</h2>
            <p class="mt-0.5 text-xs text-muted-foreground">
              Pick the theme for the whole desktop.
            </p>
          </div>

          <div class="grid grid-cols-2 gap-2">
            {#each Object.entries(THEME_LABELS) as [id, label] (id)}
              <button
                type="button"
                class="flex items-center justify-between gap-1.5 rounded-lg border px-2.5 py-1.5 text-left text-sm transition-colors {getTheme() ===
                (id as Theme)
                  ? 'border-primary/50 bg-primary/5 text-foreground'
                  : 'text-muted-foreground hover:bg-muted/50'}"
                onclick={() => pickTheme(id as Theme)}
              >
                {label}
                {#if getTheme() === (id as Theme)}<CheckIcon
                    class="size-3.5 shrink-0 text-primary"
                  />{/if}
              </button>
            {/each}
          </div>

          <Separator decorative />

          <div>
            <h3 class="text-sm font-semibold">Desktop background</h3>
            <p class="mt-0.5 text-xs text-muted-foreground">
              A subtle CSS pattern behind your icons, in the style of
              <a
                href="https://www.magicpattern.design/tools/css-backgrounds"
                target="_blank"
                rel="noreferrer">magicpattern.design</a
              >.
            </p>
          </div>

          <div class="grid grid-cols-4 gap-2">
            {#each PATTERNS as p (p.id)}
              {@const active = getBackground().pattern === p.id}
              <button
                type="button"
                class="flex flex-col items-center gap-1.5 rounded-lg border p-2 transition-colors {active
                  ? 'border-primary/60 bg-primary/5'
                  : 'border-border hover:bg-muted/50'}"
                onclick={() => setBackgroundPattern(p.id)}
                title={p.label}
              >
                <span
                  class="h-10 w-full rounded-md border border-border/60 bg-muted"
                  style={swatchStyle(p.id, getBackground().color)}
                ></span>
                <span
                  class="flex items-center gap-1 text-[11px] {active
                    ? 'font-medium text-foreground'
                    : 'text-muted-foreground'}"
                >
                  {p.label}
                  {#if active}<CheckIcon class="size-3 text-primary" />{/if}
                </span>
              </button>
            {/each}
          </div>

          <!-- Colors: pattern (foreground shapes) + an optional fill behind
             them. Fill defaults to "Auto", i.e. transparent, so the app's
             own theme background shows through the gaps — same as before
             this control existed. -->
          <div class="flex items-center justify-between gap-4">
            <Label for="bg-color" class="text-xs font-medium">Pattern color</Label>
            <div class="flex items-center gap-2">
              <input
                id="bg-color"
                type="color"
                class="size-7 cursor-pointer rounded-md border border-border bg-transparent p-0.5"
                value={getBackground().color}
                oninput={(e) => setPatternColor((e.currentTarget as HTMLInputElement).value)}
              />
              <span class="font-mono text-xs text-muted-foreground">{getBackground().color}</span>
            </div>
          </div>

          <div class="flex items-center justify-between gap-4">
            <div class="flex items-center gap-2">
              <Checkbox
                id="bg-fill-toggle"
                checked={getBackground().fillColor !== null}
                onCheckedChange={(v) => onFillToggle(!!v)}
              />
              <Label for="bg-fill-toggle" class="text-xs font-medium">Custom background fill</Label>
            </div>
            <div class="flex items-center gap-2">
              <input
                id="bg-fill-color"
                type="color"
                class="size-7 cursor-pointer rounded-md border border-border bg-transparent p-0.5 disabled:cursor-not-allowed disabled:opacity-40"
                value={getBackground().fillColor ?? fillDraft}
                disabled={getBackground().fillColor === null}
                oninput={onFillColorInput}
              />
              <span class="font-mono text-xs text-muted-foreground"
                >{getBackground().fillColor ?? 'Auto'}</span
              >
            </div>
          </div>

          <div class="flex flex-col gap-1.5">
            <div class="flex items-center justify-between">
              <Label for="bg-opacity" class="text-xs font-medium">Opacity</Label>
              <span class="font-mono text-xs text-muted-foreground"
                >{Math.round(getBackground().opacity * 100)}%</span
              >
            </div>
            <Slider
              id="bg-opacity"
              type="single"
              min={0}
              max={1}
              step={0.01}
              value={getBackground().opacity}
              onValueChange={setBackgroundOpacity}
            />
          </div>

          <div class="flex flex-col gap-1.5">
            <div class="flex items-center justify-between">
              <Label for="bg-fade" class="text-xs font-medium">Fade mask</Label>
              <span class="font-mono text-xs text-muted-foreground">
                {getBackground().fade === 0 ? 'Off' : `${Math.round(getBackground().fade * 100)}%`}
              </span>
            </div>
            <Slider
              id="bg-fade"
              type="single"
              min={0}
              max={1}
              step={0.01}
              value={getBackground().fade}
              onValueChange={setBackgroundFade}
            />
            <p class="text-[11px] text-muted-foreground">
              Fades the pattern out toward the edges, like a vignette.
            </p>
          </div>

          <div class="flex flex-col gap-1.5">
            <div class="flex items-center justify-between">
              <Label for="bg-scale" class="text-xs font-medium">Size</Label>
              <span class="font-mono text-xs text-muted-foreground"
                >{Math.round(getBackground().scale * 100)}%</span
              >
            </div>
            <Slider
              id="bg-scale"
              type="single"
              min={0.4}
              max={3}
              step={0.05}
              value={getBackground().scale}
              onValueChange={setBackgroundScale}
              disabled={noPattern}
            />
          </div>

          <div class="flex flex-col gap-1.5">
            <div class="flex items-center justify-between">
              <Label for="bg-rotation" class="text-xs font-medium">Rotation</Label>
              <span class="font-mono text-xs text-muted-foreground"
                >{Math.round(getBackground().rotation)}°</span
              >
            </div>
            <Slider
              id="bg-rotation"
              type="single"
              min={0}
              max={359}
              step={1}
              value={getBackground().rotation}
              onValueChange={setBackgroundRotation}
              disabled={noPattern}
            />
          </div>
        </div>
      {/if}
    </div>
  </div>

  <div class="shrink-0 border-t px-3 py-1.5 text-right text-[11px] text-muted-foreground">
    Oikos {VERSION}
  </div>
</div>
