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

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

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

const selectCardStyles = (styles) =>
  ['borderColor', 'borderRadius', 'borderWidth'].reduce((acc, key) => {
    if (styles[key]) acc[key] = styles[key]
    return acc
  }, {})

const selectInteractiveCardStyles = ({
  backgroundColor,
  paddingBottom,
  paddingLeft,
  paddingRight,
  paddingTop
}) => ({
  ...(backgroundColor && { backgroundColor }),
  paddingBottom,
  paddingLeft,
  paddingRight,
  paddingTop
})

const selectIconStyles = ({
  iconMarginBottom,
  iconMarginLeft,
  iconMarginRight,
  iconMarginTop
}) => ({
  marginBottom: iconMarginBottom,
  marginLeft: iconMarginLeft,
  marginRight: iconMarginRight,
  marginTop: iconMarginTop
})

const selectIconProps = ({ icon, iconBackgroundColor, iconColor }) => ({
  icon,
  variant: { background: true, padding: 'small' },
  tokens: { backgroundColor: iconBackgroundColor, color: iconColor }
})

const selectTitleStyles = ({
  titleMarginBottom,
  titleMarginLeft,
  titleMarginRight,
  titleMarginTop
}) => ({
  marginBottom: titleMarginBottom,
  marginLeft: titleMarginLeft,
  marginRight: titleMarginRight,
  marginTop: titleMarginTop
})

const selectTitleTextStyles = ({
  titleFontColor,
  titleFontName,
  titleFontSize,
  titleFontWeight,
  titleLineHeight
}) =>
  applyTextStyles({
    fontColor: titleFontColor,
    fontName: titleFontName,
    fontSize: titleFontSize,
    fontWeight: titleFontWeight,
    lineHeight: titleLineHeight
  })

const selectContentStyles = ({
  contentMarginBottom,
  contentMarginLeft,
  contentMarginRight,
  contentMarginTop
}) => ({
  marginBottom: contentMarginBottom,
  marginLeft: contentMarginLeft,
  marginRight: contentMarginRight,
  marginTop: contentMarginTop
})

const selectContentTextStyles = ({
  contentFontColor,
  contentFontName,
  contentFontSize,
  contentFontWeight,
  contentLineHeight
}) =>
  applyTextStyles({
    fontColor: contentFontColor,
    fontName: contentFontName,
    fontSize: contentFontSize,
    fontWeight: contentFontWeight,
    lineHeight: contentLineHeight
  })

const selectStatusIconProps = ({ statusIcon, statusIconColor }) => ({
  icon: statusIcon,
  tokens: { color: statusIconColor },
  variant: { size: 'micro' }
})

const selectActionIconStyles = ({
  actionIconMarginBottom,
  actionIconMarginLeft,
  actionIconMarginRight,
  actionIconMarginTop
}) => ({
  marginBottom: actionIconMarginBottom,
  marginLeft: actionIconMarginLeft,
  marginRight: actionIconMarginRight,
  marginTop: actionIconMarginTop
})

const selectActionIconProps = ({ actionIcon, actionIconColor }) => ({
  icon: actionIcon,
  tokens: { color: actionIconColor }
})

const ACTION_ICON_ANIMATION_DURATION = 100

/**
 * ActionCard component represents a card with an action that can be triggered by the user.
 *
 * @component
 * @example
 * return (
 *   <ActionCard
 *     icon={<Icon icon={Icons.EyeMasked} />}
 *     title="Like"
 *     href="/like"
 *     accessibilityRole="link"
 *     tokens={themeTokens}
 *     variant={{validation: 'warning'}}
 *     onPress={() => handleLike()}
 *   >
 *    Click here to like the post
 *   </ActionCard>
 * )
 */
export const ActionCard = React.forwardRef(
  (
    { icon, title, children, href, direction = true, accessibilityRole, tokens, variant, ...rest },
    ref
  ) => {
    const themeTokens = useThemeTokens('ActionCard', tokens, variant)

    const actionIconAnimation = React.useRef(new Animated.Value(0)).current

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

    return (
      <Card
        ref={ref}
        interactiveCard={{
          body: (pressableState) => {
            const animate = pressableState.pressed || pressableState.hover || pressableState.focus
            Animated.timing(actionIconAnimation, {
              toValue: animate ? themeTokens.actionIconTranslate : 0,
              duration: ACTION_ICON_ANIMATION_DURATION,
              useNativeDriver: false
            }).start()

            return (
              <View style={staticStyles.container}>
                {icon && (
                  <View style={selectIconStyles(themeTokens)}>
                    <Icon
                      {...selectIconProps({
                        icon,
                        ...themeTokens
                      })}
                    />
                  </View>
                )}
                <View style={staticStyles.content}>
                  <View style={staticStyles.header}>
                    <View style={[selectTitleStyles(themeTokens), staticStyles.title]}>
                      <View style={staticStyles.titleRow}>
                        {wrapStringsInText(title, {
                          style: [selectTitleTextStyles(themeTokens), staticStyles.titleText]
                        })}
                        {themeTokens.statusIcon && (
                          <View style={staticStyles.statusIcon}>
                            <Icon {...selectStatusIconProps(themeTokens)} />
                          </View>
                        )}
                      </View>
                    </View>
                    <View style={staticStyles.icons}>
                      {direction && (
                        <Animated.View
                          style={[
                            selectActionIconStyles(themeTokens),
                            { transform: [{ translateX: actionIconAnimation }] }
                          ]}
                        >
                          <Icon {...selectActionIconProps(themeTokens)} />
                        </Animated.View>
                      )}
                    </View>
                  </View>
                  <View style={[staticStyles.body, selectContentStyles(themeTokens)]}>
                    {typeof children === 'string'
                      ? wrapStringsInText(children, {
                          style: selectContentTextStyles(themeTokens)
                        })
                      : children}
                  </View>
                </View>
              </View>
            )
          },
          tokens: selectInteractiveCardStyles(themeTokens)
        }}
        tokens={selectCardStyles(themeTokens)}
        {...selectedProps}
      />
    )
  }
)

ActionCard.displayName = 'ActionCard'

ActionCard.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('ActionCard'),
  variant: variantProp.propType,
  /**
   * Icon for the ActionCard
   */
  icon: PropTypes.elementType,
  /**
   * Title for the ActionCard
   */
  title: PropTypes.string,
  /**
   * Children for the ActionCard
   */
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
  /**
   * href for the ActionCard
   */
  href: PropTypes.string,
  /**
   * Enable or disable the direction of the ActionCard
   */
  direction: PropTypes.bool,
  /**
   * AccesibilityRole for the ActionCard
   */
  accessibilityRole: PropTypes.string
}

const staticStyles = StyleSheet.create({
  body: {
    flexDirection: 'column'
  },
  container: {
    flex: 1,
    flexDirection: 'row'
  },
  content: {
    flex: 1,
    flexDirection: 'column'
  },
  icons: {
    flexDirection: 'row',
    alignItems: 'center'
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between'
  },
  title: {
    flexShrink: 1
  },
  titleRow: {
    flexDirection: 'row',
    alignItems: 'center'
  },
  titleText: {
    flexShrink: 1
  },
  statusIcon: {
    marginLeft: 4
  }
})
