import React from 'react'
import PropTypes from 'prop-types'
import { Platform, StyleSheet, View } from 'react-native'
import { viewports } from '@telus-uds/system-constants'

import { useTheme } from '../ThemeProvider/useTheme'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { useViewport } from '../ViewportProvider/useViewport'
import { a11yProps } from '../utils/props/a11yProps'
import { getTokensPropType } from '../utils/props/tokens'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { useResponsiveProp } from '../utils/useResponsiveProp'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'

import { HorizontalScroll, horizontalScrollUtils } from '../HorizontalScroll/HorizontalScroll'
import { HorizontalScrollButton } from '../HorizontalScroll/HorizontalScrollButton'

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

const { selectHorizontalScrollTokens, useItemPositions } = horizontalScrollUtils

const selectStyles = (themeTokens, maxWidth, viewport) => {
  const isDesktop =
    viewport === viewports.md || viewport === viewports.lg || viewport === viewports.xl

  return {
    wrapper: {
      alignItems: isDesktop ? 'center' : 'flex-start'
    },
    scrollContainer: {
      width: '100%',
      ...(isDesktop && { maxWidth })
    },
    container: {
      paddingTop: themeTokens.mainContainerTopPadding,
      paddingBottom: themeTokens.mainContainerBottomPadding,
      paddingLeft: themeTokens.mainContainerLeftPadding,
      paddingRight: themeTokens.mainContainerRightPadding,
      gap: themeTokens.mainContainerGap,
      ...(isDesktop && {
        alignItems: 'flex-start',
        justifyContent: 'center'
      })
    }
  }
}

/**
 * A horizontal scrollable shortcuts component that displays a collection of shortcut items.
 * This component automatically injects shared configuration props to all ShortcutsItem children
 * via React.cloneElement, including variant settings, hideLabels, and iconVariant.
 *
 * @component
 * @param {Object} props - Component properties
 * @param {Object} [props.tokens] - Theme tokens to customize the component's appearance
 * @param {Object} [props.variant] - Visual variant configuration for the shortcuts container and its items
 * @param {string} [props.variant.width] - Width variant to apply to all items (e.g., 'equal', 'dynamic')
 * @param {Object} [props.scrollButtonTokens] - Tokens to customize scroll button appearance
 * @param {boolean} [props.hideLabels=false] - Whether to hide labels on all shortcut items (can be overridden per item)
 * @param {Object} [props.iconVariant] - Icon variant to apply to all shortcut items (can be overridden per item)
 * @param {React.ReactNode} props.children - ShortcutsItem components to render
 * @param {React.Ref} ref - Forwarded ref to the component's root element
 * @returns {React.ReactElement} Rendered shortcuts component with horizontal scroll functionality
 *
 * @example
 * <Shortcuts hideLabels={false} variant={{ width: 'equal' }}>
 *   <ShortcutsItem icon={HomeIcon} label="Home" href="/home" />
 *   <ShortcutsItem icon={SettingsIcon} label="Settings" href="/settings" />
 * </Shortcuts>
 *
 * @example
 * // Item-level props override container props
 * <Shortcuts hideLabels iconVariant={{ size: 'small' }}>
 *   <ShortcutsItem icon={HomeIcon} label="Home" hideLabel={false} />
 *   <ShortcutsItem icon={SettingsIcon} label="Settings" />
 * </Shortcuts>
 */
export const Shortcuts = React.forwardRef(
  (
    { tokens, variant, scrollButtonTokens, hideLabels = false, iconVariant, children, ...rest },
    ref
  ) => {
    const viewport = useViewport()
    const themeTokens = useThemeTokens('Shortcuts', tokens, variant, {
      viewport
    })

    const { themeOptions } = useTheme()
    const maxWidth = useResponsiveProp(
      themeOptions?.contentMaxWidth,
      viewports.map.get(viewports.xl)
    )

    const [itemPositions] = useItemPositions()

    const [maxItemWidth, setMaxItemWidth] = React.useState(null)

    const registerWidth = React.useCallback(
      (width) => setMaxItemWidth((prev) => (prev == null || width > prev ? width : prev)),
      []
    )

    const styles = selectStyles(themeTokens, maxWidth, viewport)

    const childrenWithProps = React.Children.map(children, (child) => {
      if (!React.isValidElement(child)) {
        return child
      }
      return React.cloneElement(child, {
        maxWidth: maxItemWidth,
        registerWidth,
        containerVariant: variant,
        containerHideLabels: hideLabels,
        containerIconVariant: iconVariant
      })
    })

    return (
      <View style={[staticStyles.wrapper, styles.wrapper]} ref={ref} {...selectProps(rest)}>
        <View style={styles.scrollContainer}>
          <HorizontalScroll
            ScrollButton={HorizontalScrollButton}
            itemPositions={itemPositions}
            tokens={selectHorizontalScrollTokens(themeTokens)}
            scrollButtonTokens={scrollButtonTokens}
            variant={{ hideNavigationButtons: Platform.OS !== 'web' }}
          >
            <View style={[staticStyles.container, styles.container]}>{childrenWithProps}</View>
          </HorizontalScroll>
        </View>
      </View>
    )
  }
)

Shortcuts.displayName = 'Shortcuts'

Shortcuts.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('Shortcuts'),
  variant: variantProp.propType,
  /**
   * Custom tokens for `HorizontalScrollButton`
   */
  scrollButtonTokens: getTokensPropType('HorizontalScrollButton'),
  /**
   * Hide labels for all ShortcutsItem children. When true, labels are visually hidden but remain accessible to screen readers via the icon's accessibilityLabel.
   */
  hideLabels: PropTypes.bool,
  /**
   * Icon variant to apply to all ShortcutsItem children.
   */
  iconVariant: variantProp.propType,
  /**
   * ShortcutsItem components to be rendered within the Shortcuts container
   */
  children: PropTypes.node
}

const staticStyles = StyleSheet.create({
  wrapper: {
    flexGrow: 1
  },
  container: {
    flexDirection: 'row',
    flex: 1
  }
})
