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

import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { getTokensPropType } from '../utils/props/tokens'
import { variantProp } from '../utils/props/variantProp'
import { a11yProps } from '../utils/props/a11yProps'
import { viewProps } from '../utils/props/viewProps'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { getA11yPropsFromHtmlTag, layoutTags } from '../utils/a11y/semantics'
import { useViewport } from '../ViewportProvider/useViewport'

const selectDotStyles = ({ dotWidth, timelineColor, dotBorderWidth, dotColor }) => ({
  width: dotWidth,
  height: dotWidth,
  borderRadius: dotWidth / 2,
  backgroundColor: dotColor,
  borderWidth: dotBorderWidth,
  borderColor: timelineColor
})

const selectConnectorStyles = ({ timelineConnectorColor, connectorHeight, connectorWidth }) => ({
  width: connectorWidth,
  height: connectorHeight,
  backgroundColor: timelineConnectorColor
})

const selectTimelineContainerStyle = ({ timelineContainerDirection }) => ({
  flexDirection: timelineContainerDirection
})

const selectLineItemStyles = ({
  lineItemAlign,
  lineItemDirection,
  lineItemMarginBottom,
  lineItemMarginRight
}) => ({
  alignItems: lineItemAlign,
  flexDirection: lineItemDirection,
  marginBottom: lineItemMarginBottom,
  marginRight: lineItemMarginRight,
  overflow: 'hidden'
})

const selectLineItemContainer = ({ lineItemContainerDirection, lineContainerFlexSize }) => ({
  flexDirection: lineItemContainerDirection,
  flex: lineContainerFlexSize
})

const selectItemContentStyles = (
  { itemContentFlexSize, itemContentMarginBottom, itemContentMarginRight },
  isLastChild
) => {
  return {
    flex: itemContentFlexSize,
    marginBottom: !isLastChild && itemContentMarginBottom,
    marginRight: !isLastChild && itemContentMarginRight
  }
}

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

/**
 * Timeline is a component that displays either a horizontal or vertical list of the
 * children components passed by props
 *
 * ## Component API
 *
 * - `horizontal` In order to display the Component list horizontally
 *
 *
 * ## A11y guidelines
 * Timeline link supports all the common a11y props.
 */
export const Timeline = React.forwardRef(
  (
    { tokens, variant = {}, children, accessibilityLabel, tag = 'ul', childrenTag = 'li', ...rest },
    ref
  ) => {
    const viewport = useViewport()
    const themeTokens = useThemeTokens('Timeline', tokens, variant, { viewport })

    const containerProps = {
      ...selectProps(rest),
      ...getA11yPropsFromHtmlTag(tag, rest.accessibilityRole || 'list'),
      accessibilityLabel
    }

    return (
      <View {...containerProps} ref={ref} style={selectTimelineContainerStyle(themeTokens)}>
        {children.map((child, index) => {
          const accessibilityRole = Platform.OS !== 'android' ? 'listitem' : undefined
          const childrenProps = {
            ...getA11yPropsFromHtmlTag(
              childrenTag,
              child?.props?.accessibilityRole || accessibilityRole
            )
          }

          return (
            <View
              style={selectLineItemContainer(themeTokens)}
              // eslint-disable-next-line react/no-array-index-key
              key={`timeline-${index}-${child.displayName}`}
              {...childrenProps}
            >
              <View style={selectLineItemStyles(themeTokens)}>
                <View style={selectDotStyles(themeTokens)} />
                <View style={selectConnectorStyles(themeTokens)} />
              </View>
              <View style={selectItemContentStyles(themeTokens, index + 1 === children.length)}>
                {child}
              </View>
            </View>
          )
        })}
      </View>
    )
  }
)

Timeline.displayName = 'Timeline'

Timeline.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('Timeline'),
  variant: variantProp.propType,
  /**
   * A list of components that will be rendered either horizontally or vertically
   */
  children: PropTypes.arrayOf(PropTypes.node).isRequired,
  /**
   * A required accessibility label that needs to be passed to be used on List
   * which is applied as normal for a React Native accessibilityLabel prop.
   */
  accessibilityLabel: PropTypes.string.isRequired,
  /**
   * Sets the HTML tag of the outer container and the children. By default `'li'` for the children
   * and `'ul'` for the container
   *
   * If either `tag` or `childrenTag` is overridden, the other should be too, to avoid producing invalid HTML.
   *
   */
  tag: PropTypes.oneOf(layoutTags),
  /**
   * The HTML tag to render each child as
   */
  childrenTag: PropTypes.oneOf(layoutTags)
}
