import React from 'react'
import { View, Platform, StyleSheet } from 'react-native'
import PropTypes from 'prop-types'
import { StackView } from '../StackView/StackView'
import { Typography } from '../Typography/Typography'
import { RenderActivityIndicator } from './RenderActivityIndicator'
import { BACKDROP_Z_INDEX, BACKDROP_OPACITY, SPACE_WITH_LABEL, SPACE_WITHOUT_LABEL } from './shared'
import { activityIndicatorCommonProps } from './sharedProptypes'

const recursiveMap = (nodeChildren, fn) =>
  React.Children.map(nodeChildren, (child) => {
    if (!React.isValidElement(child)) return child
    if (child.props?.children) {
      return fn(
        React.cloneElement(child, {
          children: recursiveMap(child.props.children, fn)
        })
      )
    }
    return fn(child)
  })

export const OverlayIndicator = React.forwardRef(
  (
    {
      variantProps,
      label,
      labelPosition,
      labelMapping,
      children,
      inline,
      showLabel,
      isActive = true
    },
    ref
  ) => {
    const safeChildren =
      Platform.OS === 'web' && isActive
        ? recursiveMap(children, (c) =>
            React.isValidElement(c) ? React.cloneElement(c, { role: 'presentation' }) : c
          )
        : children

    // inline + children
    if (inline && children) {
      return (
        <View
          style={[staticStyles.container, Platform.OS === 'web' && staticStyles.inlineContainer]}
        >
          <View style={staticStyles.backdropContainer}>{safeChildren}</View>
          <View style={staticStyles.buttonOverlaySpinner}>
            <RenderActivityIndicator {...variantProps} ref={ref} label={label} />
          </View>
        </View>
      )
    }

    // overlay
    return (
      <View style={staticStyles.container}>
        <View style={staticStyles.backdropContainer}>{safeChildren}</View>

        <View
          style={[
            staticStyles.overlayContainer,
            Platform.OS === 'web' && staticStyles.webOverlayContainer
          ]}
        >
          <StackView
            space={showLabel ? SPACE_WITH_LABEL : SPACE_WITHOUT_LABEL}
            tokens={{ alignItems: 'center' }}
            direction={labelMapping[labelPosition]}
          >
            <RenderActivityIndicator {...variantProps} ref={ref} label={label} />
            {showLabel && <Typography>{label}</Typography>}
          </StackView>
        </View>
      </View>
    )
  }
)

OverlayIndicator.displayName = 'OverlayIndicator'

const staticStyles = StyleSheet.create({
  container: { position: 'relative' },
  inlineContainer: { display: 'inline-flex' },
  backdropContainer: { opacity: BACKDROP_OPACITY },
  overlayContainer: {
    position: 'absolute',
    top: '50%',
    left: '50%',
    ...Platform.select({
      ios: { zIndex: BACKDROP_Z_INDEX },
      android: { elevation: 5 }
    })
  },

  webOverlayContainer: {
    transform: [{ translateX: '-50%' }, { translateY: '-50%' }],
    zIndex: BACKDROP_Z_INDEX
  },

  buttonOverlaySpinner: {
    position: 'absolute',
    top: '50%',
    left: '50%',
    ...Platform.select({
      web: {
        transform: 'translate(-50%, -50%)',
        zIndex: BACKDROP_Z_INDEX
      },
      default: {
        transform: [{ translateX: -0.5 }, { translateY: -0.5 }],
        zIndex: BACKDROP_Z_INDEX
      }
    })
  }
})

OverlayIndicator.propTypes = {
  /**
   * Shared props
   * */
  ...activityIndicatorCommonProps,
  /**
   * Background color for overlay
   * */
  inline: PropTypes.bool,
  /**
   * Children on which the overlay is drawn
   * */
  children: PropTypes.node,
  /**
   * Controls whether the overlay is active and should apply the presentation role
   * */
  isActive: PropTypes.bool
}
