import { useState } from 'react';
import { Check } from 'lucide-react';
import { toast } from 'sonner';
import { Card } from '@/components/ui/card';
import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { THEMES, setTheme, useTheme, type ThemeId, type ThemeMode } from '@/lib/theme';
import {
  useAnimBg,
  setAnimBg,
  useAnimParams,
  setAnimDensity,
  setAnimSpeed,
  setAnimOpacity,
  ANIM_RANGES,
} from '@/lib/anim';
import { cn } from '@/lib/utils';

// v1.9: lifted out of pages/Settings.tsx so the SettingsPane Theme tab and
// the standalone /settings route render the same picker. Theme is global —
// not per-project, not per-session — so no contextual props are needed.

const MODES: { value: ThemeMode; label: string; hint: string }[] = [
  { value: 'dark', label: 'Dark', hint: 'Use the dark variant.' },
  { value: 'light', label: 'Light', hint: 'Use the light variant.' },
  { value: 'system', label: 'System', hint: 'Follow OS preference.' },
];

// Labelled range input for the animated-background params (boolab FX sliders).
// Native <input type=range> tinted with the theme accent — no shadcn Slider
// primitive exists in ui/.
function FxSlider({
  label,
  value,
  min,
  max,
  step,
  onChange,
}: {
  label: string;
  value: number;
  min: number;
  max: number;
  step: number;
  onChange: (v: number) => void;
}) {
  return (
    <label className="block space-y-1">
      <span className="flex items-center justify-between text-xs text-muted-foreground">
        <span>{label}</span>
        <span className="font-mono tabular-nums">{value.toFixed(2)}</span>
      </span>
      <input
        type="range"
        min={min}
        max={max}
        step={step}
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
        className="w-full cursor-pointer"
        style={{ accentColor: 'var(--primary)' }}
      />
    </label>
  );
}

export function ThemePicker() {
  const { id: currentId, mode: currentMode } = useTheme();
  const animOn = useAnimBg();
  const params = useAnimParams();
  // The slider set only applies to the canvas-background themes; density is
  // matrix-rain-only (Classic), speed/opacity apply to both fields.
  const isCanvasTheme = currentId === 'boocode-classic' || currentId === 'boocode-override';
  // Track the most recent in-flight pick so the picker can show a subtle
  // "applying…" state on the targeted card while the PATCH is in flight.
  const [pending, setPending] = useState<
    { kind: 'theme'; id: ThemeId } | { kind: 'mode'; mode: ThemeMode } | null
  >(null);

  async function pickTheme(id: ThemeId) {
    if (id === currentId || pending) return;
    setPending({ kind: 'theme', id });
    try {
      await setTheme(id, currentMode);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'failed to apply theme');
    } finally {
      setPending(null);
    }
  }

  async function pickMode(mode: ThemeMode) {
    if (mode === currentMode || pending) return;
    setPending({ kind: 'mode', mode });
    try {
      await setTheme(currentId, mode);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'failed to apply mode');
    } finally {
      setPending(null);
    }
  }

  return (
    <div className="space-y-8">
      <section className="space-y-3">
        <h2 className="text-sm font-medium">Mode</h2>
        <RadioGroup
          value={currentMode}
          onValueChange={(v) => void pickMode(v as ThemeMode)}
          className="flex flex-wrap gap-4"
        >
          {MODES.map((m) => (
            <div key={m.value} className="flex items-center gap-2">
              <RadioGroupItem id={`mode-${m.value}`} value={m.value} />
              <Label htmlFor={`mode-${m.value}`} className="cursor-pointer">
                <span className="font-medium">{m.label}</span>
                <span className="ml-2 text-xs text-muted-foreground">{m.hint}</span>
              </Label>
            </div>
          ))}
        </RadioGroup>
      </section>

      <section className="space-y-3">
        <div className="flex items-center justify-between gap-4">
          <h2 className="text-sm font-medium">Animated background</h2>
          <button
            type="button"
            role="switch"
            aria-checked={animOn}
            onClick={() => setAnimBg(!animOn)}
            className={cn(
              'relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent',
              'transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
              animOn ? 'bg-primary' : 'bg-input',
            )}
          >
            <span
              className={cn(
                'pointer-events-none block h-4 w-4 rounded-full bg-white shadow-lg ring-0 transition-transform duration-200',
                animOn ? 'translate-x-4' : 'translate-x-0',
              )}
            />
          </button>
        </div>
        <p className="text-xs text-muted-foreground">
          Disables canvas animations and CSS effects for all themes. Persisted locally.
        </p>
        {isCanvasTheme && (
          <div className={cn('grid gap-x-4 gap-y-3 sm:grid-cols-2 pt-1', !animOn && 'opacity-50')}>
            {currentId === 'boocode-classic' && (
              <FxSlider
                label="Density"
                value={params.density}
                min={ANIM_RANGES.density.min}
                max={ANIM_RANGES.density.max}
                step={ANIM_RANGES.density.step}
                onChange={setAnimDensity}
              />
            )}
            <FxSlider
              label="Speed"
              value={params.speed}
              min={ANIM_RANGES.speed.min}
              max={ANIM_RANGES.speed.max}
              step={ANIM_RANGES.speed.step}
              onChange={setAnimSpeed}
            />
            <FxSlider
              label="Opacity"
              value={params.opacity}
              min={ANIM_RANGES.opacity.min}
              max={ANIM_RANGES.opacity.max}
              step={ANIM_RANGES.opacity.step}
              onChange={setAnimOpacity}
            />
          </div>
        )}
      </section>

      <section className="space-y-3">
        <h2 className="text-sm font-medium">Theme</h2>
        <div className="grid grid-cols-2 md:grid-cols-3 gap-3">
          {THEMES.map((t) => {
            const isActive = t.id === currentId;
            const isPending = pending?.kind === 'theme' && pending.id === t.id;
            const isLightOnly = !t.supportsDark;
            const isDarkOnly = !t.supportsLight;
            return (
              <Card
                key={t.id}
                onClick={() => void pickTheme(t.id)}
                className={cn(
                  'p-3 cursor-pointer transition-colors',
                  'hover:bg-accent/10',
                  isActive && 'ring-2 ring-ring',
                  isPending && 'opacity-60',
                )}
              >
                <div className="flex items-center justify-between gap-2">
                  <div className="min-w-0">
                    <div className="font-mono text-sm truncate">{t.name}</div>
                    <div className="text-xs text-muted-foreground">{t.family}</div>
                  </div>
                  {isActive && (
                    <span className="inline-flex items-center gap-1 text-xs text-primary shrink-0">
                      <Check className="size-3" /> Selected
                    </span>
                  )}
                </div>
                <div className="flex mt-2 rounded overflow-hidden border border-border/40">
                  {t.anchors.map((hex, i) => (
                    <div
                      key={i}
                      className="flex-1 h-6"
                      style={{ backgroundColor: hex }}
                      aria-hidden="true"
                    />
                  ))}
                </div>
                {isLightOnly && (
                  <div className="mt-2 text-xs text-muted-foreground italic">Light only</div>
                )}
                {isDarkOnly && (
                  <div className="mt-2 text-xs text-muted-foreground italic">Dark only</div>
                )}
              </Card>
            );
          })}
        </div>
      </section>
    </div>
  );
}
