import styles from './Radio.module.css'
import { createContext, useContext, type ReactNode } from 'react'

interface RadioGroupContextValue {
  name: string
  value: string
  onChange: (value: string) => void
}

const RadioGroupContext = createContext<RadioGroupContextValue | null>(null)

function useRadioGroup(): RadioGroupContextValue {
  const ctx = useContext(RadioGroupContext)
  if (!ctx) {
    throw new Error('RadioItem must be used inside a RadioGroup')
  }
  return ctx
}

// ── RadioGroup ────────────────────────────────────────────────────────────────

interface RadioGroupProps {
  name: string
  value: string
  onChange: (value: string) => void
  orientation?: 'vertical' | 'horizontal'
  children?: ReactNode
  className?: string
}

export function RadioGroup({
  name,
  value,
  onChange,
  orientation = 'vertical',
  children,
  className,
}: RadioGroupProps) {
  return (
    <RadioGroupContext.Provider value={{ name, value, onChange }}>
      <div
        role="radiogroup"
        className={`${styles.group} ${styles[orientation]} ${className ?? ''}`}
      >
        {children}
      </div>
    </RadioGroupContext.Provider>
  )
}

// ── RadioItem ─────────────────────────────────────────────────────────────────

interface RadioItemProps {
  value: string
  label: ReactNode
  disabled?: boolean
}

export function RadioItem({ value, label, disabled = false }: RadioItemProps) {
  const ctx = useRadioGroup()
  const inputId = `radio-${ctx.name}-${value}`
  const isChecked = ctx.value === value

  function handleChange() {
    if (!disabled) {
      ctx.onChange(value)
    }
  }

  function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
    // Native radio keyboard behaviour fires onChange on ArrowDown/Up/Left/Right
    // but since we control the value externally we need to relay those events.
    if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
      e.preventDefault()
      const inputs = getGroupInputs(e.currentTarget)
      const next = getNextEnabled(inputs, e.currentTarget, 1)
      if (next) {
        ctx.onChange(next.value)
        next.focus()
      }
    } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
      e.preventDefault()
      const inputs = getGroupInputs(e.currentTarget)
      const prev = getNextEnabled(inputs, e.currentTarget, -1)
      if (prev) {
        ctx.onChange(prev.value)
        prev.focus()
      }
    }
  }

  return (
    <label className={`${styles.wrapper} ${disabled ? styles.wrapperDisabled : ''}`} htmlFor={inputId}>
      <input
        id={inputId}
        type="radio"
        name={ctx.name}
        value={value}
        checked={isChecked}
        disabled={disabled}
        className={styles.input}
        onChange={handleChange}
        onKeyDown={handleKeyDown}
      />
      <span className={styles.circle} aria-hidden="true" />
      {label && <span className={styles.label}>{label}</span>}
    </label>
  )
}

// ── helpers ───────────────────────────────────────────────────────────────────

function getGroupInputs(current: HTMLInputElement): HTMLInputElement[] {
  const group = current.closest('[role="radiogroup"]')
  if (!group) return []
  return Array.from(group.querySelectorAll<HTMLInputElement>('input[type="radio"]:not(:disabled)'))
}

function getNextEnabled(
  inputs: HTMLInputElement[],
  current: HTMLInputElement,
  direction: 1 | -1,
): HTMLInputElement | null {
  const idx = inputs.indexOf(current)
  if (idx === -1) return null
  const next = (idx + direction + inputs.length) % inputs.length
  return inputs[next] ?? null
}
