import type { PresetName } from '@/lib/themePresets';
import { cn } from '@/lib/utils';

// ---------------------------------------------------------------------------
// SectionHeading
// ---------------------------------------------------------------------------

export function SectionHeading({ title, description }: { title: string; description?: string }) {
  return (
    <div className="mb-5">
      <h2 className="text-[15px] font-semibold text-foreground">{title}</h2>
      {description && (
        <p className="mt-1 text-[13px] leading-[18px] text-muted-foreground">{description}</p>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// FieldGroup
// ---------------------------------------------------------------------------

export function FieldGroup({
  label,
  htmlFor,
  helpText,
  children,
}: {
  label: string;
  htmlFor: string;
  helpText?: string;
  children: React.ReactNode;
}) {
  return (
    <div className="mb-5">
      <label htmlFor={htmlFor} className="mb-1.5 block text-[13px] font-semibold text-foreground">
        {label}
      </label>
      {children}
      {helpText && (
        <p className="mt-1.5 text-[12px] leading-[16px] text-muted-foreground">{helpText}</p>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// TextInput
// ---------------------------------------------------------------------------

export function TextInput({
  id,
  value,
  onChange,
  placeholder,
  icon: Icon,
  as: Component,
  rows,
}: {
  id: string;
  value: string;
  onChange: (v: string) => void;
  placeholder?: string;
  icon?: React.ComponentType<{ className?: string }>;
  as?: 'textarea';
  rows?: number;
}) {
  const inputCls =
    'w-full rounded-md border border-border bg-card px-3 py-[7px] text-[14px] leading-[20px] text-foreground outline-none transition-shadow placeholder:text-muted-foreground/60 focus:shadow-[inset_0_0_0_2px_var(--ring)] focus:border-transparent';

  if (Component === 'textarea') {
    return (
      <textarea
        id={id}
        rows={rows ?? 3}
        value={value}
        placeholder={placeholder}
        onChange={(e) => onChange(e.target.value)}
        className={inputCls}
      />
    );
  }

  if (Icon) {
    return (
      <div className="relative">
        <Icon className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
        <input
          id={id}
          type="text"
          value={value}
          placeholder={placeholder}
          onChange={(e) => onChange(e.target.value)}
          className={`${inputCls} pl-9`}
        />
      </div>
    );
  }

  return (
    <input
      id={id}
      type="text"
      value={value}
      placeholder={placeholder}
      onChange={(e) => onChange(e.target.value)}
      className={inputCls}
    />
  );
}

// ---------------------------------------------------------------------------
// SelectInput
// ---------------------------------------------------------------------------

export function SelectInput({
  id,
  value,
  onChange,
  options,
}: {
  id: string;
  value: string;
  onChange: (v: string) => void;
  options: { value: string; label: string }[];
}) {
  return (
    <select
      id={id}
      value={value}
      onChange={(e) => onChange(e.target.value)}
      className="w-full rounded-md border border-border bg-card px-3 py-[7px] text-[14px] leading-[20px] text-foreground outline-none transition-shadow focus:shadow-[inset_0_0_0_2px_var(--ring)] focus:border-transparent"
    >
      {options.map((opt) => (
        <option key={opt.value} value={opt.value}>
          {opt.label}
        </option>
      ))}
    </select>
  );
}

// ---------------------------------------------------------------------------
// SaveBar
// ---------------------------------------------------------------------------

export function SaveBar({
  isPending,
  saved,
  error,
  onSave,
}: {
  isPending: boolean;
  saved: boolean;
  error: Error | null;
  onSave: () => void;
}) {
  return (
    <div className="flex items-center gap-3 border-t border-border pt-4">
      <button
        type="button"
        onClick={onSave}
        disabled={isPending}
        className="inline-flex items-center gap-2 rounded-md bg-primary px-4 py-[5px] text-[13px] font-medium text-primary-foreground transition-colors hover:bg-primary/85 disabled:opacity-60"
      >
        {isPending && (
          <span className="inline-block size-3.5 animate-spin rounded-full border-2 border-primary-foreground/40 border-t-primary-foreground" />
        )}
        {isPending ? 'Saving…' : 'Save'}
      </button>

      {saved && <span className="text-[13px] text-primary">✓ Saved</span>}

      {error && (
        <span className="text-[13px] text-destructive">
          {(error as Error)?.message ?? 'Save failed'}
        </span>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// RadioOption
// ---------------------------------------------------------------------------

export function RadioOption({
  value: _value,
  label,
  description,
  selected,
  onChange,
}: {
  value: string;
  label: string;
  description?: string;
  selected: boolean;
  onChange: () => void;
}) {
  return (
    <button
      type="button"
      onClick={onChange}
      className={cn(
        'flex w-full items-start gap-3 rounded-lg border px-3 py-2.5 text-left transition-colors',
        selected ? 'border-primary bg-accent/60' : 'border-border hover:bg-muted',
      )}
    >
      <span
        className={cn(
          'mt-0.5 flex size-[18px] shrink-0 items-center justify-center rounded-full border-2 transition-colors',
          selected ? 'border-primary bg-primary' : 'border-border bg-card',
        )}
      >
        {selected && <span className="size-[6px] rounded-full bg-primary-foreground" />}
      </span>
      <div className="min-w-0 flex-1">
        <p className="text-[14px] font-medium text-foreground">{label}</p>
        {description && <p className="mt-0.5 text-[12px] text-muted-foreground">{description}</p>}
      </div>
    </button>
  );
}

// ---------------------------------------------------------------------------
// Toggle
// ---------------------------------------------------------------------------

export function Toggle({
  label,
  description,
  checked,
  onChange,
}: {
  label: string;
  description?: string;
  checked: boolean;
  onChange: (v: boolean) => void;
}) {
  return (
    <button
      type="button"
      onClick={() => onChange(!checked)}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onChange(!checked);
        }
      }}
      className="flex w-full items-center justify-between gap-4 rounded-md px-3 py-2.5 text-left transition-colors hover:bg-muted"
    >
      <div className="min-w-0">
        <p className="text-[14px] font-medium text-foreground">{label}</p>
        {description && <p className="mt-0.5 text-[12px] text-muted-foreground">{description}</p>}
      </div>
      <span
        className={cn(
          'relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors',
          checked ? 'bg-primary' : 'bg-muted-foreground/40',
        )}
        role="switch"
        tabIndex={0}
        aria-checked={checked}
      >
        <span
          className={cn(
            'inline-block size-[14px] rounded-full bg-card shadow-sm transition-transform',
            checked ? 'translate-x-[18px]' : 'translate-x-[2px]',
          )}
        />
      </span>
    </button>
  );
}

// ---------------------------------------------------------------------------
// ColorSwatch — small preview dots to show a preset's accent colors.
// ---------------------------------------------------------------------------

const PRESET_SWATCH_COLORS: Record<string, [string, string, string, string]> = {
  default: ['oklch(0.205 0 0)', 'oklch(0.97 0 0)', 'oklch(0.922 0 0)', 'oklch(1 0 0)'],
  ocean: ['oklch(0.45 0.16 250)', 'oklch(0.96 0.02 220)', 'oklch(0.80 0.12 200)', 'oklch(1 0 0)'],
  forest: ['oklch(0.42 0.15 155)', 'oklch(0.95 0.03 150)', 'oklch(0.78 0.13 140)', 'oklch(1 0 0)'],
  sunset: ['oklch(0.55 0.22 30)', 'oklch(0.96 0.03 40)', 'oklch(0.82 0.14 60)', 'oklch(1 0 0)'],
  'high-contrast': ['oklch(0 0 0)', 'oklch(0.95 0 0)', 'oklch(0 0 0)', 'oklch(1 0 0)'],
  custom: ['oklch(0.55 0.2 280)', 'oklch(0.55 0.2 180)', 'oklch(0.55 0.2 80)', 'oklch(1 0 0)'],
};

export function ColorSwatch({ preset, isDark }: { preset: PresetName | string; isDark: boolean }) {
  const colors = PRESET_SWATCH_COLORS[preset] ?? PRESET_SWATCH_COLORS.custom;

  return (
    <div
      className="flex shrink-0 gap-0.5 rounded-md p-1"
      style={{ background: isDark ? 'oklch(0.205 0 0)' : 'oklch(0.97 0 0)' }}
    >
      {colors.map((c) => (
        <span
          key={c}
          className="size-3 rounded-sm border border-white/40"
          style={{ backgroundColor: c }}
        />
      ))}
    </div>
  );
}
