import { forwardRef, type ReactNode } from 'react';
import { Text, type TextProps, View, type ViewProps } from 'react-native';
import {
  RadioRoot as RadioRootPrimitive,
  RadioGroup as RadioGroupPrimitive,
  Slot,
  dataAttributes,
  mergeDataAttributes,
  useRadioContext,
  type IRadioProps,
} from '@cdx-ui/primitives';
import { cn } from '@cdx-ui/utils';
import {
  radioGroupVariants,
  radioIndicatorVariants,
  radioInnerDotVariants,
  radioLabelVariants,
  radioRootVariants,
} from './styles';

// =============================================================================
// RADIO ROOT
// =============================================================================

export interface RadioProps extends IRadioProps {
  className?: string;
  children?: ReactNode;
}

const RadioRoot = forwardRef<View, RadioProps>(({ className, children, style, ...props }, ref) => {
  const computedClassName = cn(radioRootVariants(), className);

  return (
    <RadioRootPrimitive
      ref={ref}
      className={computedClassName}
      style={style}
      {...props}
      {...mergeDataAttributes(props, dataAttributes({ slot: 'radio' }))}
    >
      <RadioIndicator />
      {children}
    </RadioRootPrimitive>
  );
});

RadioRoot.displayName = 'Radio';

// =============================================================================
// RADIO INDICATOR (styled-only, reads context for data-* styling)
// =============================================================================

/** Compound checked × invalid × active state for native Uniwind selectors (single data-field-state). */
const INDICATOR_STATES = {
  'unchecked:false:false': 'idle',
  'unchecked:true:false': 'invalid',
  'unchecked:false:true': 'active',
  'unchecked:true:true': 'invalid-active',
  'checked:false:false': 'checked',
  'checked:true:false': 'checked-invalid',
  'checked:false:true': 'checked-active',
  'checked:true:true': 'checked-invalid-active',
} as const;

export interface RadioIndicatorProps extends ViewProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const RadioIndicator = forwardRef<View, RadioIndicatorProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const { isChecked, isDisabled, isHovered, isInvalid, isReadOnly, isPressed, isFocusVisible } =
      useRadioContext();

    const checkState = isChecked ? 'checked' : 'unchecked';
    const fieldState =
      INDICATOR_STATES[
        `${checkState}:${isInvalid ? 'true' : 'false'}:${isPressed ? 'true' : 'false'}`
      ];

    const computedClassName = cn(radioIndicatorVariants(), className);
    const Comp = asChild ? Slot : View;

    return (
      <Comp
        ref={ref}
        className={computedClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(
          props,
          dataAttributes({
            slot: 'radio-indicator',
            hover: isHovered,
            checked: isChecked,
            disabled: isDisabled,
            focusVisible: isFocusVisible,
            invalid: isInvalid,
            readonly: isReadOnly,
            active: isPressed,
            fieldState,
          }),
        )}
      >
        <View
          className={cn(radioInnerDotVariants())}
          {...dataAttributes({
            checked: isChecked,
            invalid: isInvalid,
            hover: isHovered,
            fieldState,
          })}
        />
        {children}
      </Comp>
    );
  },
);

RadioIndicator.displayName = 'Radio.Indicator';

// =============================================================================
// RADIO LABEL (styled-only)
// =============================================================================

export interface RadioLabelProps extends TextProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const RadioLabel = forwardRef<Text, RadioLabelProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const computedClassName = cn(radioLabelVariants(), className);
    const Comp = asChild ? Slot : Text;

    return (
      <Comp
        ref={ref}
        className={computedClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'radio-label' }))}
      >
        {children}
      </Comp>
    );
  },
);

RadioLabel.displayName = 'Radio.Label';

// =============================================================================
// RADIO GROUP (wraps the primitive)
// =============================================================================

export interface RadioGroupProps extends ViewProps {
  className?: string;
  children?: ReactNode;
  value?: string;
  defaultValue?: string;
  onChange?: (value: string) => void;
  isDisabled?: boolean;
  isInvalid?: boolean;
  isRequired?: boolean;
  isReadOnly?: boolean;
  direction?: 'column' | 'row';
  name?: string;
  'aria-label'?: string;
  'aria-labelledby'?: string;
}

const RadioGroup = forwardRef<View, RadioGroupProps>(
  (
    {
      className,
      children,
      style,
      direction = 'column',
      value,
      defaultValue,
      onChange,
      isDisabled,
      isInvalid,
      isRequired,
      isReadOnly,
      name,
      ...viewProps
    },
    ref,
  ) => {
    const computedClassName = cn(radioGroupVariants({ direction }), className);

    return (
      <RadioGroupPrimitive
        ref={ref}
        className={computedClassName}
        style={style}
        value={value}
        defaultValue={defaultValue}
        onChange={onChange}
        isDisabled={isDisabled}
        isInvalid={isInvalid}
        isRequired={isRequired}
        isReadOnly={isReadOnly}
        name={name}
        direction={direction}
        {...viewProps}
        {...mergeDataAttributes(viewProps, dataAttributes({ slot: 'radio-group' }))}
      >
        {children}
      </RadioGroupPrimitive>
    );
  },
);

RadioGroup.displayName = 'Radio.Group';

// =============================================================================
// COMPOUND COMPONENT
// =============================================================================

type RadioCompoundComponent = typeof RadioRoot & {
  Indicator: typeof RadioIndicator;
  Label: typeof RadioLabel;
  Group: typeof RadioGroup;
};

export const Radio = Object.assign(RadioRoot, {
  Indicator: RadioIndicator,
  Label: RadioLabel,
  Group: RadioGroup,
}) as RadioCompoundComponent;
