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

import { applyTextStyles } from '../ThemeProvider/utils/styles'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { clickProps } from '../utils/props/clickProps'
import { getTokensPropType } from '../utils/props/tokens'
import { hrefAttrsProp } from '../utils/props/hrefAttrsProp'
import { linkProps } from '../utils/props/linkProps'
import { resolvePressableState } from '../utils/pressability'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { wrapStringsInText } from '../utils/children'
import { Icon } from '../Icon/Icon'

const DYNAMIC_WIDTH_VARIANT = 'dynamic'
const EQUAL_WIDTH_VARIANT = 'equal'

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

const selectPressableStyles = (tokens, widthVariant, equalWidth) => {
  const styles = {
    borderColor: tokens.borderColor,
    borderRadius: tokens.borderRadius,
    borderWidth: tokens.borderWidth,
    ...Platform.select({
      web: {
        outline: 'none'
      }
    })
  }

  if (widthVariant === DYNAMIC_WIDTH_VARIANT) {
    styles.width = 'auto'
  } else if (widthVariant === EQUAL_WIDTH_VARIANT) {
    if (equalWidth) {
      styles.width = equalWidth
    } else {
      styles.minWidth = tokens.width
    }
  } else {
    styles.width = tokens.width
  }

  return styles
}

const selectIconContainerStyles = (tokens) => ({
  paddingBottom: tokens.iconContainerPaddingBottom,
  paddingLeft: tokens.iconContainerPaddingLeft,
  paddingRight: tokens.iconContainerPaddingRight,
  paddingTop: tokens.iconContainerPaddingTop
})

const selectIconVariant = () => ({
  background: true,
  padding: 'medium'
})

const selectIconTokens = (tokens) => ({
  backgroundColor: tokens.iconBackgroundColor,
  color: tokens.iconColor,
  size: tokens.iconSize,
  width: tokens.iconWidth
})

const selectImageStyles = (tokens) => ({
  width: tokens.imageWidth,
  height: tokens.imageHeight
})

const selectLabelContainerStyles = (tokens) => ({
  paddingBottom: tokens.labelContainerPaddingBottom,
  paddingLeft: tokens.labelContainerPaddingLeft,
  paddingRight: tokens.labelContainerPaddingRight,
  paddingTop: tokens.labelContainerPaddingTop
})

const selectTitleTextStyles = (tokens) =>
  applyTextStyles({
    fontColor: tokens.labelFontColor,
    fontName: tokens.labelFontName,
    fontSize: tokens.labelFontSize,
    fontWeight: tokens.labelFontWeight,
    lineHeight: tokens.labelLineHeight,
    textDecorationLine: tokens.labelUnderline,
    textAlign: tokens.labelTextAlign
  })

/**
 * A clickable shortcut item component that displays an icon or image with an optional label.
 * Can be used within a Shortcuts container to create a grid of navigation shortcuts.
 *
 * @component
 * @param {Object} props - Component props
 * @param {string} [props.icon] - Icon identifier to display
 * @param {Object} [props.image={ src: '', alt: '' }] - Image object with src and alt properties
 * @param {string} [props.image.src] - Image source URL
 * @param {string} [props.image.alt] - Image alt text for accessibility
 * @param {string|React.ReactNode} props.label - Label text or content to display below the icon/image
 * @param {boolean} [props.hideLabel=false] - Whether to hide the label for this specific item
 * @param {string} [props.href] - Link URL for navigation
 * @param {Object} [props.iconVariant] - Icon variant to apply to this specific item
 * @param {Object} [props.tokens] - Theme tokens to customize appearance
 * @param {Object} [props.variant] - Variant configuration object for this specific item
 * @param {string} [props.variant.width] - Width variant (e.g., 'dynamic', 'equal')
 * @param {Function} [props.onPressableStateChange] - Callback function that receives the pressable state object (pressed, hovered, focused)
 * @param {number} [props.maxWidth] - Maximum width for equal width variant (injected by Shortcuts container)
 * @param {Function} [props.registerWidth] - Callback to register width for equal width variant (injected by Shortcuts container)
 * @param {Object} [props.containerVariant] - Variant configuration from Shortcuts container (injected by Shortcuts container)
 * @param {boolean} [props.containerHideLabels] - Hide labels setting from Shortcuts container (injected by Shortcuts container)
 * @param {Object} [props.containerIconVariant] - Icon variant from Shortcuts container (injected by Shortcuts container)
 * @param {React.Ref} ref - Forwarded ref to the Pressable component
 * @returns {React.ReactElement} The rendered shortcut item
 *
 * @example
 * <ShortcutsItem
 *   icon={HomeIcon}
 *   label="Home"
 *   href="/home"
 *   onPressableStateChange={(state) => console.log(state)}
 * />
 */
export const ShortcutsItem = React.forwardRef(
  (
    {
      icon,
      image = { src: '', alt: '' },
      label,
      hideLabel = false,
      href,
      iconVariant,
      tokens,
      variant,
      onPressableStateChange,
      maxWidth,
      registerWidth,
      containerVariant,
      containerHideLabels,
      containerIconVariant,
      ...rest
    },
    ref
  ) => {
    const mergedVariant = { ...containerVariant, ...variant }
    const widthVariant = mergedVariant?.width
    const shouldHideLabel = hideLabel || containerHideLabels
    const mergedIconVariant = iconVariant ?? containerIconVariant

    const getThemeTokens = useThemeTokensCallback('ShortcutsItem', tokens, mergedVariant)
    const getTokens = (pressableState) => getThemeTokens(resolvePressableState(pressableState))

    const { onPress, ...props } = clickProps.toPressProps(rest)
    const { hrefAttrs, rawRest } = hrefAttrsProp.bundle(props)
    const selectedProps = selectProps({
      href,
      onPress: linkProps.handleHref({ href, onPress }),
      hrefAttrs,
      ...rawRest
    })

    const handleLayout = (event) => {
      if (widthVariant === EQUAL_WIDTH_VARIANT && registerWidth) {
        const { width } = event.nativeEvent.layout
        registerWidth(width)
      }
    }

    return (
      <Pressable
        ref={ref}
        style={(pressableState) =>
          selectPressableStyles(getTokens(pressableState), widthVariant, maxWidth)
        }
        onLayout={handleLayout}
        {...selectedProps}
      >
        {(pressableState) => {
          const themeTokens = getTokens(pressableState)

          if (onPressableStateChange) {
            onPressableStateChange(resolvePressableState(pressableState))
          }

          return (
            <View style={staticStyles.container}>
              {icon && (
                <View style={selectIconContainerStyles(themeTokens)}>
                  <Icon
                    icon={icon}
                    variant={mergedIconVariant ?? selectIconVariant()}
                    tokens={mergedIconVariant ? {} : selectIconTokens(themeTokens)}
                    {...(Platform.OS === 'web' && { accessibilityLabel: label })}
                  />
                </View>
              )}
              {!icon && image && (
                <Image
                  source={image.src}
                  alt={image.alt}
                  style={selectImageStyles(themeTokens)}
                  resizeMethod="resize"
                  accessibilityIgnoresInvertColors
                />
              )}
              {label && !shouldHideLabel && (
                <View style={[staticStyles.label, selectLabelContainerStyles(themeTokens)]}>
                  {wrapStringsInText(label, { style: selectTitleTextStyles(themeTokens) })}
                </View>
              )}
            </View>
          )
        }}
      </Pressable>
    )
  }
)

ShortcutsItem.displayName = 'ShortcutsItem'

ShortcutsItem.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('ShortcutsItem'),
  variant: variantProp.propType,
  /**
   * Icon for the ShortcutsItem
   */
  icon: PropTypes.elementType,
  /**
   * Image for the ShortcutsItem
   */
  image: PropTypes.shape({
    src: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
    alt: PropTypes.string
  }),
  /**
   * Label for the ShortcutsItem
   */
  label: PropTypes.string,
  /**
   * Hide the label for this specific ShortcutsItem. When true, the label is visually hidden but remains accessible to screen readers via the icon's accessibilityLabel.
   */
  hideLabel: PropTypes.bool,
  /**
   * href for the ShortcutsItem
   */
  href: PropTypes.string,
  /**
   * Icon variant for this specific ShortcutsItem
   */
  iconVariant: variantProp.propType,
  /**
   * Callback function that receives the pressable state object containing pressed, hovered, and focused boolean properties
   */
  onPressableStateChange: PropTypes.func,
  /**
   * Maximum width for equal width variant (automatically injected by Shortcuts container)
   * @private
   */
  maxWidth: PropTypes.number,
  /**
   * Callback to register width for equal width variant (automatically injected by Shortcuts container)
   * @private
   */
  registerWidth: PropTypes.func,
  /**
   * Variant configuration from Shortcuts container (automatically injected by Shortcuts container)
   * @private
   */
  containerVariant: variantProp.propType,
  /**
   * Hide labels setting from Shortcuts container (automatically injected by Shortcuts container)
   * @private
   */
  containerHideLabels: PropTypes.bool,
  /**
   * Icon variant from Shortcuts container (automatically injected by Shortcuts container)
   * @private
   */
  containerIconVariant: variantProp.propType
}

const staticStyles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center'
  },
  label: {
    flexWrap: 'wrap',
    alignContent: 'stretch'
  }
})
