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

import { applyTextStyles } from '../ThemeProvider/utils/styles'
import { useTheme } from '../ThemeProvider/useTheme'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { getTokensPropType, selectTokens } from '../utils/props/tokens'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { StackView } from '../StackView/StackView'

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

const selectStyles = (tokens) => selectTokens('Feedback', tokens)

const selectTitleTextStyles = ({ titleFontSize, ...tokens }, themeOptions) =>
  applyTextStyles({
    ...selectTokens('Typography', { ...tokens, fontSize: titleFontSize, themeOptions }),
    themeOptions
  })
const selectContentTextStyles = ({ contentFontSize, ...tokens }, themeOptions) =>
  applyTextStyles({
    ...selectTokens('Typography', { ...tokens, fontSize: contentFontSize }),
    themeOptions
  })

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

const selectIconContainerStyles = ({ iconGap }) => ({
  paddingRight: iconGap
})

/**
 * A feedback box commonly used with form fields.
 *
 * ### Standalone usage
 * While its primary use is to facilitate feedback states for other form components such as `TextInput`,
 * you may use it standalone.
 *
 * ### Complex content
 * You may pass any React tree as the children of this component, bear in mind that a render function
 * is better suited for styling children based on Feedback's variant.
 *
 * ### Using a render function
 * When a function is passed for rendering content, it will receive the feedback text styles and
 * variant as arguments.
 *
 * ### Accessibility
 * All accessibility props set on this component will be applied to the outer container.
 */
export const Feedback = React.forwardRef(
  ({ title, children, id, validation, tokens, variant, ...rest }, ref) => {
    const themeTokens = useThemeTokens('Feedback', tokens, {
      ...variant,
      validation
    })
    const { space } = themeTokens

    const { icon: IconComponent } = themeTokens

    const { themeOptions } = useTheme()
    const titleTextStyles = selectTitleTextStyles(themeTokens, themeOptions)
    const contentTextStyles = selectContentTextStyles(themeTokens, themeOptions)

    const content =
      typeof children === 'string' ? <Text style={contentTextStyles}>{children}</Text> : children

    const selectedProps = selectProps({
      accessibilityRole: validation === 'error' ? 'alert' : undefined,
      ...rest
    })

    return (
      <View ref={ref} style={selectStyles(themeTokens)} nativeID={id} {...selectedProps}>
        <StackView space={space}>
          {title !== undefined && (
            <View style={staticStyles.title}>
              {IconComponent && (
                <View style={selectIconContainerStyles(themeTokens)}>
                  <IconComponent {...selectIconTokens(themeTokens)} />
                </View>
              )}
              <Text style={titleTextStyles}>{title}</Text>
            </View>
          )}
          {content && typeof content === 'function'
            ? content({ textStyles: contentTextStyles, variant })
            : content}
        </StackView>
      </View>
    )
  }
)
Feedback.displayName = 'Feedback'

Feedback.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Emphasized summary of the feedback. If an icon is set, it is rendered next to the title.
   */
  title: PropTypes.string,
  /**
   * Feedback content rendered below the title. A render function `({textStyles, variant}) => {}` is supported.
   */
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
  /**
   * Use to visually mark the Feedback as valid or invalid.
   */
  validation: PropTypes.oneOf(['error', 'success']),
  /** @ignore */
  id: PropTypes.string,
  tokens: getTokensPropType('Feedback'),
  variant: variantProp.propType
}

const staticStyles = StyleSheet.create({
  title: {
    display: 'flex',
    flexDirection: 'row'
  }
})
