import React from 'react'
import PropTypes from 'prop-types'
import { StyleSheet, Text, View } from 'react-native'

import { applyTextStyles } from '../ThemeProvider/utils/styles'
import { useTheme } from '../ThemeProvider/useTheme'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { focusHandlerProps } from '../utils/props/handlerProps'
import { getTokensPropType, selectTokens } from '../utils/props/tokens'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { useInputValue } from '../utils/input'
import { useUniqueId } from '../utils/useUniqueId'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { PressableCardBase, selectPressableCardTokens } from '../Card/PressableCardBase'
import { StackView } from '../StackView/StackView'
import { CheckboxButton, selectCheckboxTokens } from '../Checkbox/CheckboxButton'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([
  a11yProps,
  focusHandlerProps,
  viewProps
])

export const CheckboxCard = React.forwardRef(
  (
    {
      tokens,
      variant,
      title,
      children,
      inactive,
      defaultChecked,
      checked,
      name: inputName,
      value,
      id,
      iconId,
      onChange,
      ...rest
    },
    ref
  ) => {
    const {
      currentValue: isChecked,
      setValue: setIsChecked,
      isControlled
    } = useInputValue({
      value: checked,
      initialValue: defaultChecked,
      onChange
    })

    const handleChange = (event) => {
      if (!inactive) {
        setIsChecked(!isChecked, event)
      }
    }
    const uniqueId = useUniqueId('CheckboxCard')
    const inputId = id ?? uniqueId

    const uniqueIconId = useUniqueId('CheckboxIcon')
    const iconCheckboxId = iconId ?? uniqueIconId

    const getTokens = useThemeTokensCallback('CheckboxCard', tokens, variant)
    const getCardTokens = (cardState) => selectPressableCardTokens(getTokens(cardState))
    const { themeOptions } = useTheme()

    const selectedProps = selectProps({
      accessibilityRole: 'checkbox',
      accessibilityState: { checked: isChecked, disabled: inactive },
      ...rest
    })

    return (
      <PressableCardBase
        ref={ref}
        inactive={inactive}
        checked={isChecked}
        tokens={getCardTokens}
        onPress={handleChange}
        {...selectedProps}
      >
        {(cardState) => {
          const { checkboxSpace, contentSpace, ...themeTokens } = getTokens(cardState)
          const checkboxTokens = selectCheckboxTokens(themeTokens, 'checkbox')
          const titleTokens = selectTokens('Typography', themeTokens)
          const textStyle = applyTextStyles({ ...titleTokens, themeOptions })
          return (
            <StackView direction="row" space={checkboxSpace}>
              <View style={[staticStyles.alignWithText, { height: textStyle.lineHeight }]}>
                <CheckboxButton
                  tokens={checkboxTokens}
                  isControlled={isControlled}
                  isChecked={isChecked}
                  inactive={inactive}
                  defaultChecked={defaultChecked}
                  inputId={inputId}
                  iconId={iconCheckboxId}
                  handleChange={handleChange}
                  name={inputName}
                  value={value}
                />
              </View>
              <StackView direction="column" space={contentSpace} tokens={{ flexShrink: 1 }}>
                {title ? <Text style={textStyle}>{title}</Text> : null}
                {typeof children === 'function' ? children(cardState, textStyle) : children}
              </StackView>
            </StackView>
          )
        }}
      </PressableCardBase>
    )
  }
)
CheckboxCard.displayName = 'CheckboxCard'

CheckboxCard.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Content to be displayed at the top of the card alongside the checkbox
   */
  title: PropTypes.string,
  /**
   * Additional content to be displayed below the checkbox.
   */
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
  /**
   * Use `checked` for controlled checkbox. For uncontrolled checkbox, use the `defaultChecked` prop.
   */
  checked: PropTypes.bool,
  /**
   * Use `defaultChecked` to provide the initial value for an uncontrolled checkbox.
   */
  defaultChecked: PropTypes.bool,
  /**
   * An optional checkboxdescription.
   */
  description: PropTypes.string,
  /**
   * Checkbox card ID.
   */
  id: PropTypes.string,
  /**
   * Checkbox icon ID.
   */
  iconId: PropTypes.string,
  /**
   * Whether the corresponding input is disabled or active.
   */
  inactive: PropTypes.bool,
  /**
   * The label.
   */
  label: PropTypes.string,
  /**
   * Associate this checkbox card with a group (set as the name attribute).
   */
  name: PropTypes.string,
  /**
   * Whether the underlying input triggered a validation error or not.
   */
  error: PropTypes.bool,
  /**
   * The value. Must be unique within the group.
   */
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
  /**
   * Callback called when a controlled checkbox card gets interacted with.
   */
  onChange: PropTypes.func,
  /**
   * checkbox card tokens.
   */
  tokens: getTokensPropType('CheckboxCard'),
  /**
   * checkbox variant.
   */
  variant: variantProp.propType
}

const staticStyles = StyleSheet.create({
  alignWithText: {
    justifyContent: 'center'
  }
})
