import React from 'react'
import PropTypes from 'prop-types'
import { StyleSheet, Pressable, Image, View } from 'react-native'
import { useCarousel } from './CarouselContext'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { useViewport } from '../ViewportProvider/useViewport'
import { Icon } from '../Icon/Icon'

const selectPressableTokens = ({ borderColor, borderRadius, borderWidth, margin, padding }) => ({
  borderColor,
  borderRadius,
  borderWidth,
  margin,
  padding
})

// Play icon overlay appearance is consistent across all brands and is not theme-configurable.
// The circle occupies 55% of the thumbnail size, and the icon occupies 55% of the circle diameter.
const PLAY_ICON_RATIO = 0.55
const PLAY_ICON_BORDER_RADIUS_DIVISOR = 2

const selectImageStyles = (size) => ({
  width: size,
  height: size
})

const selectSelectedStyles = ({ selectedBorderColor, selectedBorderWidth, padding, margin }) => ({
  borderColor: selectedBorderColor,
  borderWidth: selectedBorderWidth,
  padding: padding - selectedBorderWidth,
  marginBottom: margin + selectedBorderWidth
})

const selectNonSelectedStyles = ({ borderWidth, padding, margin, selectedBorderWidth }) => ({
  padding: padding - borderWidth,
  marginBottom: margin + selectedBorderWidth
})

const selectPlayIconCircleStyles = (thumbnailSize) => {
  const diameter = thumbnailSize * PLAY_ICON_RATIO
  return {
    width: diameter,
    height: diameter,
    borderRadius: diameter / PLAY_ICON_BORDER_RADIUS_DIVISOR
  }
}

const selectPlayIconTokens = (thumbnailSize) => ({
  size: thumbnailSize * PLAY_ICON_RATIO * PLAY_ICON_RATIO
})

/**
 * `CarouselThumbnail` is used to wrap the content of an individual slide and is suppsoed to be the
 * only top-level component passed to the `Carousel`
 */
export const CarouselThumbnail = React.forwardRef(
  ({ accessibilityLabel, alt, index, isVideo, src }, ref) => {
    const { activeIndex, itemLabel, totalItems, getCopyWithPlaceholders, goTo } = useCarousel()
    const getThumbnailTokens = useThemeTokensCallback('CarouselThumbnail')
    const viewport = useViewport()
    const thumbnailTitle =
      alt ??
      getCopyWithPlaceholders('stepTrackerLabel')
        .replace(/%\{itemLabel\}/g, itemLabel)
        .replace(/%\{stepNumber\}/g, index)
        .replace(/%\{stepCount\}/g, totalItems)
    const handlePress = () => goTo(index)
    const handleKeyDown = (event) => {
      // Allow using the spacebar for navigation
      if (event?.key === ' ') goTo(index)
    }
    const {
      borderWidth,
      padding,
      selectedBorderColor,
      selectedBorderWidth,
      size,
      margin,
      playIcon
    } = getThumbnailTokens({ viewport })

    return (
      <Pressable
        key={src}
        onKeyDown={handleKeyDown}
        onPress={handlePress}
        style={({ hovered, pressed, focused }) => {
          const pressableStyles = selectPressableTokens(
            getThumbnailTokens({
              hover: hovered,
              pressed,
              focus: focused
            })
          )

          return [
            pressableStyles,
            index === activeIndex
              ? [
                  selectSelectedStyles({
                    selectedBorderColor,
                    selectedBorderWidth,
                    padding,
                    margin
                  }),
                  staticStyles.selectedPressableOutline
                ]
              : selectNonSelectedStyles({ borderWidth, padding, margin, selectedBorderWidth })
          ]
        }}
        ref={ref}
      >
        <View style={[staticStyles.imageContainer, selectImageStyles(size)]}>
          <Image
            accessibilityIgnoresInvertColors
            accessibilityLabel={accessibilityLabel ?? alt}
            source={src}
            style={selectImageStyles(size)}
            title={thumbnailTitle}
          />
          {isVideo && playIcon && (
            <View
              style={staticStyles.playIconOverlayContainer}
              testID={`play-icon-overlay-${index}`}
            >
              <View
                style={[selectPlayIconCircleStyles(size), staticStyles.playIconCircleBackground]}
              >
                <Icon
                  icon={playIcon}
                  tokens={{
                    ...selectPlayIconTokens(size),
                    color: staticStyles.playIconSymbol.color
                  }}
                />
              </View>
            </View>
          )}
        </View>
      </Pressable>
    )
  }
)

CarouselThumbnail.displayName = 'CarouselThumbnail'

CarouselThumbnail.propTypes = {
  /** Accessibility label for screen readers, overrides the alt text */
  accessibilityLabel: PropTypes.string,
  /** Alt text for the thumbnail image */
  alt: PropTypes.string,
  /** Zero-based index of this thumbnail within the carousel */
  index: PropTypes.number,
  /**
   * When true, renders a play icon overlay on the thumbnail to indicate that the slide contains a video.
   */
  isVideo: PropTypes.bool,
  /** Image source URI (web) or local asset require() (native) */
  src: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
}

const staticStyles = StyleSheet.create({
  imageContainer: {
    position: 'relative'
  },
  playIconOverlayContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center'
  },
  selectedPressableOutline: { outlineStyle: 'none' },
  playIconCircleBackground: {
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
    justifyContent: 'center',
    alignItems: 'center'
  },
  playIconSymbol: { color: 'rgb(255, 255, 255)' }
})
