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

import { CheckboxInput } from './CheckboxInput'
import { applyShadowToken } from '../ThemeProvider/utils/styles'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { getTokensSetPropType, selectTokens } from '../utils/props/tokens'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { viewProps } from '../utils/props/viewProps'

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

const selectInputStyles = (
  {
    iconBackgroundColor,
    inputBorderColor,
    inputBorderRadius,
    inputBorderWidth,
    inputBackgroundColor,
    inputHeight,
    inputOutlineColor,
    inputOutlineWidth,
    inputOutlineOffset,
    inputShadow,
    inputWidth
  },
  isChecked
) => ({
  borderColor: inputBorderColor,
  borderWidth: inputBorderWidth,
  borderRadius: inputBorderRadius,
  backgroundColor: isChecked ? iconBackgroundColor : inputBackgroundColor,
  height: inputHeight,
  width: inputWidth,
  ...applyShadowToken(inputShadow),
  ...Platform.select({
    web: {
      outlineStyle: 'solid',
      outlineColor: inputOutlineColor,
      outlineWidth: inputOutlineWidth,
      outlineOffset: inputOutlineOffset
    }
  })
})

const selectIconTokens = ({ icon, iconColor, iconSize }) => ({
  icon,
  color: iconColor,
  size: iconSize
})

const tokenKeys = [
  'checkedBackgroundColor',
  'checkedSize',
  'inputBackgroundColor',
  'inputBorderColor',
  'inputBorderWidth',
  'inputOutlineColor',
  'inputOutlineWidth',
  'inputSize',
  'outerBorderColor',
  'outerBorderWidth',
  'outerBorderGap',
  'inputSize'
]

export const selectCheckboxTokens = (themeTokens, prefix) =>
  selectTokens(tokenKeys, themeTokens, prefix)

/**
 * The visual toggle of a checkbox input. Is not interactive on its own, should be used inside
 * an interactive parent that passes down props when interacted with. Used in CheckboxCard
 */
export const CheckboxButton = React.forwardRef(
  (
    {
      isChecked,
      tokens,
      inactive,
      defaultChecked,
      inputId,
      iconId,
      isControlled,
      handleChange,
      name: inputName,
      value,
      ...rest
    },
    ref
  ) => {
    const { icon: IconComponent, ...stateTokens } = useThemeTokens('Checkbox', tokens, {
      checked: isChecked
    })
    const iconTokens = selectIconTokens(stateTokens)

    return (
      <View {...selectProps(rest)}>
        <View
          style={[staticStyles.defaultInputStyles, selectInputStyles(stateTokens, isChecked)]}
          testID={inputId}
        >
          <CheckboxInput
            ref={ref}
            checked={isChecked}
            defaultChecked={defaultChecked}
            disabled={inactive}
            id={inputId}
            isControlled={isControlled}
            onChange={handleChange}
            name={inputName}
            value={value}
          />
          {isChecked && IconComponent && (
            <View testID={iconId}>
              <IconComponent {...iconTokens} />
            </View>
          )}
        </View>
      </View>
    )
  }
)
CheckboxButton.displayName = 'CheckboxButton'

CheckboxButton.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Use `checked` for controlled Checkbox. For uncontrolled Checkbox, use the `defaultChecked` prop.
   */
  isChecked: PropTypes.bool,
  /**
   * Checkbox tokens.
   */
  tokens: getTokensSetPropType(tokenKeys, { allowFunction: true }),
  /**
   * Whether the corresponding input is disabled or active.
   */
  inactive: PropTypes.bool,
  /**
   * Use `defaultChecked` to provide the initial value for an uncontrolled Checkbox.
   */
  defaultChecked: PropTypes.bool,
  /**
   * Checkbox input ID.
   */
  inputId: PropTypes.string,
  /**
   * Checkbox icon ID.
   */
  iconId: PropTypes.string,
  /**
   * Can control the checkbox on the card.
   */
  isControlled: PropTypes.bool,
  /**
   * Callback called when a controlled checkbox gets interacted with.
   */
  handleChange: PropTypes.func,
  /**
   * Associate this checkbox with a group (set as the name attribute).
   */
  name: PropTypes.string,
  /**
   * The value of the checkbox: true or false
   */
  value: PropTypes.bool
}

const staticStyles = StyleSheet.create({
  container: { flexDirection: 'row', alignItems: 'center' },
  defaultInputStyles: { alignItems: 'center', justifyContent: 'center' }
})
