import React from 'react'
import PropTypes from 'prop-types'
import { Platform, View, Text, StyleSheet } from 'react-native'
import { Icon, iconComponentPropTypes } from './Icon'
import { getStackedContent } from '../StackView/getStackedContent'
import { spacingProps } from '../utils/props/spacingProps'

/**
 * Returns an icon and some text with a sized gap between them. This is a utility component
 * intended for use when creating components, not intended for use in applications on its own.
 *
 * IconText does not wrap its children, so should be used either:
 *  - inline within a <Text> element
 *  - within a container with `flexDirection: 'row'`
 */
export const IconText = React.forwardRef(
  ({ space, iconPosition = 'left', icon: IconComponent, iconProps, children }, ref) => {
    const iconContent = IconComponent && (
      <Icon ref={ref} icon={IconComponent} scalesWithText {...iconProps} />
    )

    // Inline images on Android are always baseline-aligned which makes them look misaligned - offset it.
    // See abandoned issue https://github.com/facebook/react-native/issues/6529
    const size = iconProps?.tokens?.size ?? 0
    const valueTranslateY = iconProps?.tokens?.translateY
    /**
     * These calculations were carried out using a set of linear equations to calculate that the
     * position of the icon "->"" is aligned to the first line of the tooltip text on IOS and Android.
     * The issue was mainly on IOS, the translateY style didn't match with the old calculations.
     */
    const resultY = valueTranslateY ? Math.floor(-1 * (valueTranslateY - 4)) : 0

    const iconAdjustedAndroid = (
      <View style={{ transform: [{ translateY: valueTranslateY ? size * 0.2 : size * 0.01 }] }}>
        {iconContent}
      </View>
    )

    const iconAdjustedIOS = (
      <View style={{ transform: [{ translateY: valueTranslateY ? resultY : size * 0.01 }] }}>
        {iconContent}
      </View>
    )

    const mobile = Platform.OS === 'android' ? iconAdjustedAndroid : iconAdjustedIOS
    const adjustedContainer = Platform.OS === 'web' ? iconContent : mobile

    const adjustedContainerWithPosition = (
      <View style={staticStyles.adjustedContainer}>{adjustedContainer}</View>
    )

    if (iconPosition === 'inline') {
      return (
        <Text>
          {children} {adjustedContainerWithPosition}
        </Text>
      )
    }

    return getStackedContent(
      iconPosition === 'left' ? [adjustedContainer, children] : [children, adjustedContainer],
      { space, direction: 'row' }
    )
  }
)
IconText.displayName = 'IconText'

IconText.propTypes = {
  /**
   * Amount of space to separate the text content and icon. Uses the themes's spacing scale
   * (see useSpacingScale for more info).
   */
  space: spacingProps.types.spacingValue,
  /**
   * Whether the icon should be to the left of the content, the right of the content or inline with the content.
   */
  iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
  /**
   * A valid UDS icon component imported from a UDS palette.
   */
  icon: PropTypes.elementType,
  /**
   * Props that will be passed to the icon component. By default the icon's `scalesWithText`
   * prop will be set as "true" so that the icon continues to match the size of the text
   * if users use accessibility settings to increase text size.
   */
  iconProps: PropTypes.exact(iconComponentPropTypes),
  /**
   * Content to be rendered alongside the Icon component. Usually this should be a
   * `<Typography>` component, or a component that renders `<Text>`.
   */
  children: PropTypes.node
}

const staticStyles = StyleSheet.create({
  adjustedContainer: {
    position: 'absolute'
  }
})
