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 { LabelContent } from './LabelContent'
import { Tooltip } from '../Tooltip/Tooltip.native'
import { propTypes as tooltipPropTypes } from '../Tooltip/shared'

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

const selectLabelStyles = (tokens, themeOptions) =>
  applyTextStyles({ ...selectTokens('Typography', tokens), themeOptions })

const selectHintStyles = (
  { hintColor, hintFontName, hintFontSize, hintFontWeight, hintLineHeight },
  themeOptions
) =>
  applyTextStyles({
    color: hintColor,
    fontName: hintFontName,
    fontSize: hintFontSize,
    fontWeight: hintFontWeight,
    lineHeight: hintLineHeight,
    themeOptions
  })

const selectGapStyles = ({ gap }) => ({ marginRight: gap })

export const InputLabel = React.forwardRef(
  (
    {
      copy = 'en',
      label,
      forId,
      hint,
      hintPosition = 'inline',
      hintId,
      tooltip,
      tokens,
      variant,
      characterCount,
      maxCharacterAllowed,
      ...rest
    },
    ref
  ) => {
    const themeTokens = useThemeTokens('InputLabel', tokens, variant)

    const hasTooltip = tooltip !== undefined

    const isHintInline = hintPosition === 'inline'

    const { themeOptions } = useTheme()

    const getTooltipProps = () => {
      return typeof tooltip === 'string' ? { content: tooltip } : tooltip
    }
    return (
      <>
        <View ref={ref} style={staticStyles.container} {...selectProps(rest)}>
          <Text
            style={[
              selectLabelStyles(themeTokens, themeOptions),
              selectGapStyles(themeTokens),
              staticStyles.label
            ]}
          >
            <LabelContent forId={forId}>{label}</LabelContent>
          </Text>
          {hint && isHintInline && (
            <Text
              style={[
                selectHintStyles(themeTokens, themeOptions),
                hasTooltip && selectGapStyles(themeTokens),
                staticStyles.label
              ]}
              nativeID={hintId}
            >
              {hint}
            </Text>
          )}
          {hasTooltip && (
            <View
              style={[
                staticStyles.tooltipAlign,
                {
                  height: themeTokens.fontSize * themeTokens.lineHeight,
                  color: themeTokens.color
                }
              ]}
            >
              <Tooltip copy={copy} {...getTooltipProps()} />
            </View>
          )}
          {maxCharacterAllowed && isHintInline && (
            <Text style={[selectHintStyles({ ...themeTokens }), staticStyles.characterCountlabel]}>
              {characterCount}/{maxCharacterAllowed}
            </Text>
          )}
        </View>
        {hint && !maxCharacterAllowed && !isHintInline && (
          <Text style={[selectHintStyles(themeTokens), staticStyles.hintBelow]} nativeID={hintId}>
            {hint}
          </Text>
        )}
        {hint && maxCharacterAllowed && !isHintInline && (
          <View style={staticStyles.container}>
            <Text
              style={[selectHintStyles(themeTokens), staticStyles.flexHintBelow]}
              nativeID={hintId}
            >
              {hint}
            </Text>
            <Text style={[selectHintStyles(themeTokens), staticStyles.characterCountlabel]}>
              {characterCount}/{maxCharacterAllowed}
            </Text>
          </View>
        )}
      </>
    )
  }
)
InputLabel.displayName = 'InputLabel'

InputLabel.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Whether the English or French copy will be used (e.g. for accessibility labels).
   */
  copy: PropTypes.oneOf(['en', 'fr']),
  /**
   * The input label.
   */
  label: PropTypes.string.isRequired,
  /**
   * The id attribute of the input which this label refers to.
   */
  forId: PropTypes.string,
  /**
   * A short description of the expected input.
   */
  hint: PropTypes.string,
  /**
   * Position of the hint relative to label. Use `below` to display a larger hint below the label.
   */
  hintPosition: PropTypes.oneOf(['inline', 'below']),
  /**
   * The id attribute passed down to the hint element.
   */
  hintId: PropTypes.string,
  /**
   * Content of an optional `Tooltip`. If set, a tooltip button will be shown next to the label.
   */
  tooltip: PropTypes.oneOfType([PropTypes.shape(tooltipPropTypes), PropTypes.string]),
  /**
   * Current number of characterts of an input text.
   */
  characterCount: PropTypes.number,
  /**
   * Max number of characters that allows an input text.
   */
  maxCharacterAllowed: PropTypes.number,
  tokens: getTokensPropType('InputLabel'),
  variant: variantProp.propType
}

const staticStyles = StyleSheet.create({
  container: {
    flexShrink: 1,
    flexDirection: 'row'
  },
  characterCountlabel: {
    marginLeft: 'auto',
    marginTop: 'auto'
  },
  label: {
    flexShrink: 1,
    alignSelf: 'center'
  },
  hintBelow: {
    flexBasis: '100%',
    flexShrink: 0
  },
  flexHintBelow: {
    flexBasis: '100%',
    flexShrink: 1
  },
  tooltipAlign: {
    alignSelf: 'center',
    justifyContent: 'center'
  }
})
