import { useId } from 'react'

interface SliderProps {
  label: string
  value: number
  min: number
  max: number
  step?: number
  unit?: string
  format?: (v: number) => string
  hint?: string
  onChange: (v: number) => void
}

/** Labelled range with a live tabular readout. The whole row is the control;
 *  the track fill mirrors the value so the eye reads position without the number. */
export function Slider({ label, value, min, max, step = 1, unit, format, hint, onChange }: SliderProps) {
  const id = useId()
  const pct = max === min ? 0 : ((value - min) / (max - min)) * 100
  const shown = format ? format(value) : `${value}${unit ?? ''}`
  return (
    <div className="group">
      <div className="flex items-baseline justify-between gap-2">
        <label htmlFor={id} className="text-xs font-medium text-ink-muted group-focus-within:text-ink">
          {label}
        </label>
        <span className="font-mono text-sm text-ink tnum">{shown}</span>
      </div>
      <input
        id={id}
        type="range"
        min={min}
        max={max}
        step={step}
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
        className="sx-range mt-2 w-full"
        style={{ '--fill': `${pct}%` } as React.CSSProperties}
      />
      {hint && <p className="mt-1 text-[11px] leading-snug text-ink-faint">{hint}</p>}
    </div>
  )
}

interface StepperProps {
  label: string
  value: number
  min?: number
  max?: number
  step?: number
  unit?: string
  onChange: (v: number) => void
}

/** Discrete +/− for exact integer counts (catalog sizes) where dragging is fiddly. */
export function Stepper({ label, value, min = 0, max = 999, step = 1, unit, onChange }: StepperProps) {
  const clamp = (v: number) => Math.max(min, Math.min(max, v))
  return (
    <div className="flex items-center justify-between gap-3">
      <span className="text-xs font-medium text-ink-muted">{label}</span>
      <div className="flex items-center gap-1">
        <button
          type="button"
          aria-label={`decrease ${label}`}
          onClick={() => onChange(clamp(value - step))}
          disabled={value <= min}
          className="grid size-7 place-items-center rounded-sm border border-hairline bg-raised
                     text-ink-muted transition-colors hover:bg-overlay hover:text-ink
                     focus-visible:outline focus-visible:outline-2 focus-visible:outline-melodic
                     disabled:opacity-30"
        >
          –
        </button>
        <span className="w-12 text-center font-mono text-sm text-ink tnum">
          {value}
          {unit && <span className="text-ink-faint">{unit}</span>}
        </span>
        <button
          type="button"
          aria-label={`increase ${label}`}
          onClick={() => onChange(clamp(value + step))}
          disabled={value >= max}
          className="grid size-7 place-items-center rounded-sm border border-hairline bg-raised
                     text-ink-muted transition-colors hover:bg-overlay hover:text-ink
                     focus-visible:outline focus-visible:outline-2 focus-visible:outline-melodic
                     disabled:opacity-30"
        >
          +
        </button>
      </div>
    </div>
  )
}

interface ToggleProps {
  label: string
  checked: boolean
  hint?: string
  onChange: (v: boolean) => void
}

/** Switch for an on/off layer (e.g. running Bandcamp alongside the distributor). */
export function Toggle({ label, checked, hint, onChange }: ToggleProps) {
  return (
    <div>
      <button
        type="button"
        role="switch"
        aria-checked={checked}
        onClick={() => onChange(!checked)}
        className="flex w-full items-center justify-between gap-3 text-left"
      >
        <span className="text-xs font-medium text-ink-muted">{label}</span>
        <span
          className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border transition-colors ${
            checked ? 'border-melodic/60 bg-melodic/30' : 'border-hairline bg-overlay'
          }`}
        >
          <span
            className={`inline-block size-3.5 rounded-full bg-ink transition-transform ${
              checked ? 'translate-x-4.5' : 'translate-x-0.5'
            }`}
          />
        </span>
      </button>
      {hint && <p className="mt-1 text-[11px] leading-snug text-ink-faint">{hint}</p>}
    </div>
  )
}

/** A grouped block of controls under a quiet section heading. */
export function Group({ title, glyph, children }: { title: string; glyph: string; children: React.ReactNode }) {
  return (
    <section className="space-y-4">
      <h3 className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-widest text-ink-faint">
        <span aria-hidden className="text-ink-muted">
          {glyph}
        </span>
        {title}
      </h3>
      {children}
    </section>
  )
}
