'use client'

import { createContext, useContext, useId, type ComponentProps, type ReactNode } from 'react'

import type { GDSComponentProps } from '@graphprotocol/gds-css'

import { useGDS } from '../hooks/index.ts'
import { cn, splitProps } from '../utils/index.ts'
import { Checkable, type CheckableLabelProps } from './base/Checkable.tsx'
import type { RadioMeta } from './Radio.meta.ts'

export interface RadioProps
  extends
    Omit<ComponentProps<'input'>, 'checked' | 'defaultChecked' | 'onChange' | 'size' | 'type'>,
    GDSComponentProps<typeof RadioMeta> {
  name?: string | undefined
  value?: string | undefined
  checked?: boolean | undefined
  defaultChecked?: boolean | undefined
  onChange?: ((checked: true) => void) | undefined
  /** @default false */
  disabled?: boolean | undefined
  children?: ReactNode | undefined
}

export function RadioRoot({
  size,
  children: label,
  'aria-label': ariaLabel,
  'aria-labelledby': ariaLabelledBy,
  name: passedName,
  value,
  checked: controlledChecked,
  defaultChecked,
  onChange,
  disabled = false,
  className,
  ...props
}: RadioProps) {
  useGDS()

  const { rootProps, nestedProps } = splitProps(props)

  const groupContext = useContext(RadioGroupContext)
  const name = passedName ?? groupContext?.name

  return (
    <Checkable
      size={size}
      label={label}
      aria-label={ariaLabel}
      aria-labelledby={ariaLabelledBy}
      name={name}
      value={value}
      checked={controlledChecked ?? defaultChecked}
      disabled={disabled}
      className={cn('gds-radio', className)}
      {...rootProps}
      renderInput={(renderProps, { inputProps }) => (
        <Checkable.Box {...renderProps} className={cn(renderProps.className, 'rounded-full')}>
          <input
            {...inputProps}
            type="radio"
            checked={controlledChecked}
            defaultChecked={defaultChecked}
            onChange={(event) => onChange?.(event.target.checked as true)}
            {...nestedProps}
          />
          <span
            className={`
              rounded-full bg-(--text-color-form-checked) transition-opacity
              @state-unchecked/checkable:hidden
              @state-disabled/checkable:opacity-disabled
              @prop-size-small/checkable:size-1
              @prop-size-medium/checkable:size-1.5
              @prop-size-large/checkable:size-2
            `}
          />
        </Checkable.Box>
      )}
    />
  )
}
RadioRoot.displayName = 'Radio'

const RadioGroupContext = createContext<{ name: string } | null>(null)

export interface RadioGroupProps extends ComponentProps<'div'> {
  name?: string | undefined
  /**
   * TODO: Accept `value`, `defaultValue`, and `onChange` for a `SegmentedControl`-like API, as an
   * alternative to `checked` / `defaultChecked` on the `Radio` components themselves?
   */
}

export function RadioGroup({ name: passedName, children, ...props }: RadioGroupProps) {
  const uniqueId = useId()
  const name = passedName ?? `gds-radio-${uniqueId}`

  return (
    <RadioGroupContext.Provider value={{ name }}>
      <div data-name={name} {...props}>
        {children}
      </div>
    </RadioGroupContext.Provider>
  )
}
RadioGroup.displayName = 'Radio.Group'

export interface RadioAreaProps extends CheckableLabelProps {}

export function RadioArea(props: RadioAreaProps) {
  return <Checkable.Label {...props} />
}
RadioArea.displayName = 'Radio.Area'
