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

import { applyTextStyles } from '../ThemeProvider/utils/styles'
import { useTheme } from '../ThemeProvider/useTheme'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { clickProps } from '../utils/props/clickProps'
import { getTokensPropType, selectTokens } from '../utils/props/tokens'
import { linkProps } from '../utils/props/linkProps'
import { resolvePressableTokens } from '../utils/pressability'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { withLinkRouter } from '../utils/withLinkRouter'
import { Spacer } from '../Spacer/Spacer'
import { horizontalScrollUtils } from '../HorizontalScroll/HorizontalScroll'

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

const { itemPositionsPropType, getItemPositionLayoutHandler } = horizontalScrollUtils

const selectHighlightBarStyles = ({
  highlightColor,
  highlightBarBorderRadius = 0,
  highlightBarBorderWidth = 0,
  highlightBarHeight = 0
}) => ({
  backgroundColor: highlightColor,
  borderColor: highlightColor,
  height: highlightBarHeight + highlightBarBorderWidth * 2,
  borderRadius: highlightBarBorderRadius,
  borderWidth: highlightBarBorderWidth,
  bottom: -1 * (highlightBarHeight + highlightBarBorderWidth),
  left: 0,
  right: 0,
  zIndex: 1 + highlightBarBorderWidth
})

const selectHighlightTriangleStyles = ({ highlightColor, highlightTriangleSize }) => ({
  container: {
    bottom: 0 - highlightTriangleSize * 2
  },
  triangle: {
    height: 0,
    width: 0,
    borderWidth: highlightTriangleSize,
    borderTopColor: highlightColor,
    borderBottomColor: 'transparent',
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent'
  }
})

const selectContainerStyles = ({
  backgroundColor,
  borderColor,
  borderWidth = 0,
  borderRadius,
  paddingHorizontal = 0,
  paddingVertical = 0,
  marginHorizontal = 0,
  marginVertical = 0
}) => ({
  backgroundColor,
  borderColor,
  borderWidth,
  borderRadius,
  paddingHorizontal: paddingHorizontal - borderWidth,
  paddingVertical: paddingVertical - borderWidth,
  marginLeft: marginHorizontal,
  marginRight: marginHorizontal,
  marginTop: marginVertical,
  marginBottom: marginVertical
})

/**
 * Item within a Tabs component representing one tab of content. May be rendered as a link
 * or as a "menuitem" button depending on whether 'href' is passed.
 *
 * This is rendered automatically by `Tabs` and isn't intended be used directly.
 */
const TabsItemInner = React.forwardRef(
  (
    {
      href,
      variant,
      tokens,
      selected,
      itemPositions,
      index,
      children,
      accessibilityRole,
      accessibilityCurrent = Platform.OS === 'web' && accessibilityRole === 'link' && selected
        ? 'page'
        : undefined,
      accessibilityState = accessibilityRole === 'tab' ? { selected } : undefined,
      id,
      render,
      ...rawRest
    },
    ref
  ) => {
    // Convert onClick etc to onPress etc if used in an integration
    const { onPress, ...rest } = clickProps.toPressProps(rawRest)
    const { themeOptions } = useTheme()
    const getTokens = useThemeTokensCallback('TabsItem', tokens, variant)
    const resolveTokens = (pressableState) =>
      resolvePressableTokens(getTokens, pressableState, { selected })

    const getPressableStyle = (pressableState) => {
      const { maxWidth } = resolveTokens(pressableState)
      return [{ maxWidth }, Platform.OS === 'web' && { outline: 'none' }]
    }

    const handleLayout = getItemPositionLayoutHandler(itemPositions.positions, index)

    // On press, update the selection, call any press handler, and open any href in platform-appropriate way
    const openHref = href && linkProps.handleHref({ href })
    const handlePress =
      onPress || openHref
        ? (...args) => {
            if (onPress) onPress(...args)
            if (openHref) openHref(...args)
          }
        : undefined

    const selectedProps = selectProps({
      accessibilityRole,
      accessibilityCurrent,
      accessibilityState,
      ...rest
    })

    React.useEffect(() => {
      // If this is selected while off-screen, scroll it into view
      if (selected) {
        const position = itemPositions.positions[index]
        const scrollEnd = itemPositions.scrollOffset + itemPositions.containerWidth
        if (
          // is off the right edge, or
          (scrollEnd && position?.end > scrollEnd) ||
          // is off the left edge
          (typeof position?.start === 'number' && position.start < itemPositions.scrollOffset)
        ) {
          itemPositions.scrollTo(position.start)
        }
      }
      // itemPositions is a ref object so this should only re-run when `selected` (or `index`) change
    }, [selected, index, itemPositions])

    if (render) return render({ selected, handlePress })

    return (
      <Pressable
        ref={ref}
        onPress={handlePress}
        href={href}
        style={getPressableStyle}
        onLayout={handleLayout}
        nativeID={id}
        {...selectedProps}
      >
        {(pressableState) => {
          const { space, textAlign, ...themeTokens } = resolveTokens(pressableState)

          const hasHighlightBar = Boolean(themeTokens.highlightBarHeight)
          const highlightBarStyle = hasHighlightBar && selectHighlightBarStyles(themeTokens)

          const hasHighlightTriangle = Boolean(themeTokens.highlightTriangleSize)
          const highlightTriangleStyle =
            hasHighlightTriangle && selectHighlightTriangleStyles(themeTokens)

          const containerStyles = selectContainerStyles(themeTokens)
          const textStyles = applyTextStyles({
            ...selectTokens('Typography', themeTokens),
            themeOptions,
            textAlign
          })

          return (
            <View style={staticStyles.container}>
              <View style={containerStyles}>
                <Text style={textStyles}>{children}</Text>
              </View>
              <Spacer space={space} />
              {hasHighlightBar && <View style={[staticStyles.absolute, highlightBarStyle]} />}
              {hasHighlightTriangle && (
                <View style={[staticStyles.absolute, highlightTriangleStyle.container]}>
                  <View style={highlightTriangleStyle.triangle} />
                </View>
              )}
            </View>
          )
        }}
      </Pressable>
    )
  }
)
TabsItemInner.displayName = 'TabsItem'

TabsItemInner.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('TabsItem'),
  variant: variantProp.propType,
  onPress: PropTypes.func,
  href: PropTypes.string,
  index: PropTypes.number,
  selected: PropTypes.bool,
  itemPositions: itemPositionsPropType,
  children: PropTypes.string,
  id: PropTypes.string,
  render: PropTypes.func
}

const staticStyles = StyleSheet.create({
  center: {
    alignItems: 'center'
  },
  absolute: {
    position: 'absolute',
    alignItems: 'center',
    left: 0,
    right: 0
  },
  container: {
    flexGrow: 1,
    alignItems: 'center',
    justifyContent: 'center',
    ...Platform.select({
      web: {
        pointerEvents: 'none'
      }
    })
  }
})

export const TabsItem = withLinkRouter(TabsItemInner)
