import React from 'react'
import PropTypes from 'prop-types'
import { Platform } from 'react-native'
import { Link } from '../Link/Link'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { htmlAttrs } from '../utils/htmlAttrs'
import { viewProps } from '../utils/props/viewProps'
import { selectSystemProps } from '../utils/props/selectSystemProps'

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

const alignSelfMap = {
  start: 'flex-start',
  middle: 'center',
  end: 'flex-end'
}

// The ExpandCollapseControl has all the appropriate role, a11y, press handling etc
// and a more appropriate press area, defer interaction handling to it.
const presentationOnly = {
  accessibilityRole: null, // Treat as regular flow content with the Control
  pointerEvents: 'none', // Stop RNW from stopping clicks from bubbling to Control
  focusable: false // Stop RNW from setting tabIndex={0}: focus goes to Control only
}

export const ExpandCollapseMiniControl = React.forwardRef(
  (
    {
      pressableState,
      collapseTitle,
      expandTitle = collapseTitle,
      iconPosition = 'right',
      tokens,
      variant = {},
      align,
      ...rest
    },
    ref
  ) => {
    const { expanded, hover, focus, pressed } = pressableState || {}
    const { quiet } = variant
    const isFocusVisible = Platform.OS === 'web' ? focus && !pressed && !hover : expanded

    const linkTokens = useThemeTokens(
      'Link',
      {},
      { ...variant, quiet },
      {
        focus: isFocusVisible,
        hover,
        pressed
      }
    )
    const { fontSize, lineHeight, iconSize, icon } = useThemeTokens(
      'ExpandCollapseMiniControl',
      tokens,
      variant,
      {
        expanded,
        focus
      }
    )

    // Choose hover styles when any part of Control is hoverred
    const appearance = { ...variant, hover }

    const getTokens = (linkState) => {
      const { hover: linkHover } = linkState || {}
      const isHovered = hover || linkHover

      const iconBaselineOffset = 0
      const hoverTranslateY = 4

      const fontBaseline = fontSize / hoverTranslateY
      const iconBaseline = iconSize / hoverTranslateY
      const staticOffset = hoverTranslateY
      const sizeCompensation = -Math.abs(iconSize - fontSize)

      const baselineAlignment = fontBaseline + iconBaseline - staticOffset + sizeCompensation

      const mobileAdjustment = Platform.OS !== 'web' ? -2 : 0

      if (isHovered) {
        const hoverMovementDistance = 1.3
        const animationOffset = expanded
          ? -(hoverTranslateY * hoverMovementDistance)
          : hoverTranslateY

        return {
          iconTranslateY:
            baselineAlignment + iconBaselineOffset + animationOffset + mobileAdjustment
        }
      }

      return { iconTranslateY: baselineAlignment + iconBaselineOffset + mobileAdjustment }
    }

    return (
      <Link
        variant={appearance}
        icon={icon}
        iconPosition={iconPosition}
        tokens={(linkState) => ({
          ...linkTokens,
          ...getTokens(linkState),
          iconSize,
          blockFontSize: fontSize,
          blockLineHeight: lineHeight,
          ...(align && { alignSelf: alignSelfMap[align] })
        })}
        ref={ref}
        {...presentationOnly}
        {...selectProps(rest)}
      >
        {expanded ? expandTitle : collapseTitle}
      </Link>
    )
  }
)

ExpandCollapseMiniControl.displayName = 'ExpandCollapseMiniControl'

ExpandCollapseMiniControl.propTypes = {
  ...selectedSystemPropTypes,
  ...Link.propTypes,
  /**
   * Optional function to call on pressing the panel's control, in addition to opening or closing the panel
   */
  onPress: PropTypes.func,
  /**
   * ExpandCollapseMiniControl title when expanded
   */
  expandTitle: PropTypes.string.isRequired,
  /**
   * ExpandCollapseMiniControl title when collapsed
   */
  collapseTitle: PropTypes.string.isRequired,
  /**
   * React Native's `Pressable`'s state object
   */
  pressableState: PropTypes.object,
  /**
   * Optional variant object to override the default theme tokens
   */
  variant: PropTypes.object,
  /**
   * Controls the horizontal alignment of the trigger label and icon
   */
  align: PropTypes.oneOf(['start', 'middle', 'end'])
}
