'use client'

import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon'
import type { VariantProps } from '@gluestack-ui/nativewind-utils'
import { tva } from '@gluestack-ui/nativewind-utils/tva'
import { useStyleContext, withStyleContext } from '@gluestack-ui/nativewind-utils/withStyleContext'
import { createRadio } from '@gluestack-ui/radio'
import { cssInterop } from 'nativewind'
import { Circle } from 'phosphor-react-native'
import * as PhosphorIcons from 'phosphor-react-native'
import React, { ReactNode } from 'react'
import { Pressable, View, ViewProps } from 'react-native'

import Text from '../text'

const SCOPE = 'Radio'

const IndicatorWrapper = React.forwardRef<React.ComponentRef<typeof View>, ViewProps & { states?: any }>(
  function IndicatorWrapper({ ...props }, ref) {
    const { size: parentSize } = useStyleContext(SCOPE)
    return (
      <View className="relative">
        {props.states.active && (
          <View
            className={radioOnTapStyle({
              parentVariants: {
                size: parentSize,
              },
            })}
          />
        )}
        <View {...props} ref={ref} />
      </View>
    )
  },
)

const UIRadio = createRadio({
  Root: withStyleContext(Pressable, SCOPE) as ReturnType<typeof withStyleContext<typeof Pressable>>,
  Group: View,
  Icon: UIIcon,
  Indicator: IndicatorWrapper,
  Label: Text,
})

cssInterop(PrimitiveIcon, {
  className: {
    target: 'style',
    nativeStyleToProp: {
      height: true,
      width: true,
      fill: true,
      color: 'classNameColor',
      stroke: true,
    },
  },
})

const radioStyle = tva({
  base: 'group/radio flex-row items-center justify-start',
  variants: {
    size: {
      md: 'gap-2',
      lg: 'gap-2',
    },
  },
})

const radioGroupStyle = tva({
  base: 'gap-2',
})

const radioIconStyle = tva({
  base: 'items-center justify-center rounded-full fill-selector-foreground',

  parentVariants: {
    size: {
      md: 'size-[var(--radio-icon-size)]',
      lg: 'size-[var(--lg-radio-icon-size)]',
    },
  },
})

const radioIndicatorStyle = tva({
  base: 'items-center justify-center rounded-full border-selector-border bg-selector-background data-[checked=true]:border-selector-border-active data-[checked=true]:bg-selector-accent-true data-[invalid=true]:border-destructive-border data-[active=true]:data-[checked=true]:bg-selector-accent-onTap data-[active=true]:data-[checked=true]:border-selector-border-active data-[active=true]:!border-selector-border-onTap data-[disabled=true]:border-disabled-border data-[disabled=true]:bg-disabled',
  parentVariants: {
    size: {
      md: 'size-[var(--radio-size)] border-[length:var(--radio-border-size)]',
      lg: 'size-[var(--lg-radio-size)] border-[length:var(--lg-radio-border-size)]',
    },
  },
})

const radioLabelStyle = tva({
  base: '',
})

const radioOnTapStyle = tva({
  base: 'absolute rounded-full bg-selector-accent-onTap opacity-5',
  parentVariants: {
    size: {
      lg: '-left-[calc(var(--lg-radio-onTap-size)/2-var(--lg-radio-size)/2)] -top-[calc(var(--lg-radio-onTap-size)/2-var(--lg-radio-size)/2)] size-[var(--lg-radio-onTap-size)]',
      md: '-left-[calc(var(--radio-onTap-size)/2-var(--radio-size)/2)] -top-[calc(var(--radio-onTap-size)/2-var(--radio-size)/2)] size-[var(--radio-onTap-size)]',
    },
  },
})

type IRadioProps = Omit<React.ComponentProps<typeof UIRadio>, 'context'> & VariantProps<typeof radioStyle>
const RadioWrapper = React.forwardRef<React.ComponentRef<typeof UIRadio>, IRadioProps>(function Radio(
  { className, size = 'md', ...props },
  ref,
) {
  return <UIRadio className={radioStyle({ class: className, size })} {...props} ref={ref} context={{ size }} />
})

type IRadioGroupProps = React.ComponentProps<typeof UIRadio.Group> & VariantProps<typeof radioGroupStyle>
const RadioGroup = React.forwardRef<React.ComponentRef<typeof UIRadio.Group>, IRadioGroupProps>(function RadioGroup(
  { className, ...props },
  ref,
) {
  return <UIRadio.Group className={radioGroupStyle({ class: className })} {...props} ref={ref} />
})

type IRadioIndicatorProps = React.ComponentProps<typeof UIRadio.Indicator> & VariantProps<typeof radioIndicatorStyle>
const RadioIndicator = React.forwardRef<React.ComponentRef<typeof UIRadio.Indicator>, IRadioIndicatorProps>(
  function RadioIndicator({ className, ...props }, ref) {
    const { size } = useStyleContext(SCOPE)
    return (
      <UIRadio.Indicator
        className={radioIndicatorStyle({
          parentVariants: { size },
          class: className,
        })}
        ref={ref}
        {...props}
      />
    )
  },
)

type IRadioLabelProps = React.ComponentProps<typeof UIRadio.Label> & VariantProps<typeof radioIndicatorStyle>
const RadioLabel = React.forwardRef<React.ComponentRef<typeof UIRadio.Label>, IRadioLabelProps>(function RadioLabel(
  { className, children, ...props },
  ref,
) {
  const { size } = useStyleContext(SCOPE)

  return (
    <UIRadio.Label
      ref={ref}
      {...props}
      className={radioLabelStyle({
        parentVariants: { size },
        class: className,
      })}
    >
      {typeof children === 'string' ? (
        <Text variant="p" className="group-data-[invalid=true]/radio:text-destructive-background">
          {children}
        </Text>
      ) : (
        children
      )}
    </UIRadio.Label>
  )
})

type IRadioIconProps = React.ComponentProps<typeof UIRadio.Icon> &
  VariantProps<typeof radioIconStyle> & {
    height?: number
    width?: number
    weight?: PhosphorIcons.IconWeight
  }
const RadioIcon = React.forwardRef<React.ComponentRef<typeof UIRadio.Icon>, IRadioIconProps>(function RadioIcon(
  { className, size, ...props },
  ref,
) {
  const { size: parentSize } = useStyleContext(SCOPE)

  if (typeof size === 'number') {
    return <UIRadio.Icon ref={ref} {...props} className={radioIconStyle({ class: className })} size={size} />
  } else if ((props.height !== undefined || props.width !== undefined) && size === undefined) {
    return <UIRadio.Icon ref={ref} {...props} className={radioIconStyle({ class: className })} />
  }

  return (
    <UIRadio.Icon
      {...props}
      className={radioIconStyle({
        parentVariants: {
          size: parentSize,
        },
        size,
        class: className,
      })}
      ref={ref}
    />
  )
})

const Radio: React.FC<IRadioProps & { label?: ReactNode }> = ({ label, ...props }) => {
  return (
    <RadioWrapper {...props}>
      <RadioIndicator>
        <RadioIcon as={Circle} weight="fill" />
      </RadioIndicator>
      {label && <RadioLabel>{label}</RadioLabel>}
    </RadioWrapper>
  )
}
RadioWrapper.displayName = 'RadioWrapper'
RadioGroup.displayName = 'RadioGroup'
RadioIndicator.displayName = 'RadioIndicator'
RadioLabel.displayName = 'RadioLabel'
RadioIcon.displayName = 'RadioIcon'

export { Radio, RadioWrapper, RadioGroup, RadioIndicator, RadioLabel, RadioIcon }
