import React from 'react'
import PropTypes from 'prop-types'

import { View, Pressable, Platform, StyleSheet } from 'react-native'
import { resolvePressableTokens } from '../utils/pressability'
import { applyShadowToken } from '../ThemeProvider/utils/styles'
import { getTokensPropType } from '../utils/props/tokens'
import { Tooltip } from '../Tooltip/Tooltip.native'
import { UNAVAILABLE_VARIANT } from './constants'

const selectGeneralBubbleTokens = ({
  outerBubbleHeight,
  outerBubbleWidth,
  outerBubbleContentAlignItems,
  outerBubbleJustifyContent,
  bubbleBorderColor,
  bubbleBorderWidth,
  bubbleBorderRadius
}) => ({
  height: outerBubbleHeight,
  width: outerBubbleWidth,
  justifyContent: outerBubbleContentAlignItems,
  alignItems: outerBubbleJustifyContent,
  borderColor: bubbleBorderColor,
  borderWidth: bubbleBorderWidth,
  borderRadius: bubbleBorderRadius,
  ...Platform.select({ web: { outline: 'none' } })
})

const selectInnerBubbleTokens = ({
  innerBubbleHeight,
  innerBubbleWidth,
  innerBubbleBorderRadius,
  borderColor,
  borderWidth,
  shadow
}) => ({
  height: innerBubbleHeight,
  width: innerBubbleWidth,
  borderRadius: innerBubbleBorderRadius,
  borderColor,
  borderWidth,
  ...applyShadowToken(shadow)
})

const selectBorderBubbleTokens = ({
  bubbleBorderColor,
  bubbleBorderWidth,
  bubbleBorderRadius
}) => ({
  borderColor: bubbleBorderColor,
  borderWidth: bubbleBorderWidth,
  borderRadius: bubbleBorderRadius
})

const selectOverlayStyles = ({ overlayColor, innerBubbleBorderRadius }) => ({
  borderRadius: innerBubbleBorderRadius,
  backgroundColor: overlayColor
})

const selectSlashStyles = (
  { slashLightColor, slashDarkColor, slashWidth, slashOffset },
  unavailable
) => ({
  width: slashWidth,
  backgroundColor: unavailable === UNAVAILABLE_VARIANT.DARK ? slashDarkColor : slashLightColor,
  marginLeft: slashOffset
})

export const ColorBubble = React.forwardRef(
  (
    {
      tokens = () => ({}),
      id,
      colorHexCode,
      colorName,
      isSelected,
      onPress,
      showTooltip,
      unavailable,
      isDisabled
    },
    ref
  ) => {
    const defaultTokens = tokens({ selected: isSelected })

    const resolveColorBubbleTokens = (pressState) =>
      resolvePressableTokens(tokens, isDisabled ? {} : pressState, {})

    const themeTokens = tokens()

    const pressable = (
      <Pressable
        style={(state) => [
          selectGeneralBubbleTokens(resolveColorBubbleTokens(state)),
          isSelected && selectBorderBubbleTokens(defaultTokens)
        ]}
        onPress={onPress}
        disabled={isDisabled}
        focusable={!isDisabled}
        accessible
        accessibilityRole="radio"
        accessibilityLabel={colorName}
        accessibilityState={{ checked: isSelected, disabled: isDisabled }}
        ref={ref}
        testID={id}
      >
        <View style={[selectInnerBubbleTokens(themeTokens), { backgroundColor: colorHexCode }]}>
          {unavailable && (
            <View style={[StyleSheet.absoluteFillObject, selectOverlayStyles(themeTokens)]} />
          )}
        </View>
        {unavailable && (
          <View style={[staticStyles.indicator, selectSlashStyles(themeTokens, unavailable)]} />
        )}
      </Pressable>
    )

    if (showTooltip) {
      return (
        <Tooltip content={colorName} activateOnHover>
          {pressable}
        </Tooltip>
      )
    }

    return pressable
  }
)
ColorBubble.displayName = 'ColorBubble'

ColorBubble.propTypes = {
  /**
   * Color toggle tokens callback.
   */
  tokens: getTokensPropType('ColorToggle'),
  /**
   * ID of each color bubble
   */
  id: PropTypes.string,
  /**
   * Hexadecimal code for the background of the color bubble
   */
  colorHexCode: PropTypes.string,
  /**
   * Name of the color bubble
   */
  colorName: PropTypes.string,
  /**
   * If the current color bubble is selected
   */
  isSelected: PropTypes.bool,
  /**
   * If provided, this function is called when the current selection
   * of the color is changed of all currently `items`.
   * Receives two parameters: item object selected and the event
   */
  onPress: PropTypes.func,
  /**
   * When true, wraps the bubble in a Tooltip that displays the colorName on hover (web only).
   */
  showTooltip: PropTypes.bool,
  /**
   * When set, renders a diagonal indicator over the bubble. Accepts either 'dark' or 'light' to determine the color of the indicator.
   */
  unavailable: PropTypes.oneOf(Object.values(UNAVAILABLE_VARIANT)),
  /**
   * When true, disables interaction on the bubble.
   */
  isDisabled: PropTypes.bool
}

const staticStyles = StyleSheet.create({
  indicator: {
    position: 'absolute',
    top: '50%',
    height: 2,
    transform: [{ rotate: '-45deg' }]
  }
})
