import React from 'react'
import PropTypes from 'prop-types'

import { applyInheritance } from '../helpers'
import { BaseView } from '../../utils/BaseView/BaseView'
import { StyleSheet, createMediaQueryStyles } from '../../utils/ssr-media-query/ssr-media-query'
import { useTheme } from '../../ThemeProvider/useTheme'
import { useViewport } from '../../ViewportProvider/useViewport'

const horizontalAlignStyles = (horizontalAlign) => {
  switch (horizontalAlign) {
    case 'start':
      return {
        justifyContent: 'flex-start',
        textAlign: 'left'
      }
    case 'center':
      return {
        justifyContent: 'center',
        textAlign: 'center'
      }
    case 'end':
      return {
        justifyContent: 'flex-end',
        textAlign: 'right'
      }
    default:
      return {}
  }
}

const verticalAlignStyles = (verticalAlign) => {
  switch (verticalAlign) {
    case 'top':
      return { alignItems: 'flex-start' }
    case 'middle':
      return { alignItems: 'center' }
    case 'bottom':
      return { alignItems: 'flex-end' }
    default:
      return {}
  }
}

const distributeStyles = (distribute) => {
  switch (distribute) {
    case 'between':
      return { justifyContent: 'space-between' }
    case 'around':
      return { justifyContent: 'space-around' }
    default:
      return {}
  }
}

export const FlexGridRow = React.forwardRef(
  (
    {
      horizontalAlign,
      verticalAlign,
      distribute,
      xsReverse,
      smReverse,
      mdReverse,
      lgReverse,
      xlReverse,
      children,
      ...rest
    },
    ref
  ) => {
    const {
      themeOptions: { enableMediaQueryStyleSheet }
    } = useTheme()
    const viewport = useViewport()
    const staticStyles = {
      width: '100%',
      marginVertical: 0,
      marginHorizontal: 'auto',
      flexGrow: 0,
      flexShrink: 1,
      flexBasis: 'auto',
      ...horizontalAlignStyles(horizontalAlign),
      ...verticalAlignStyles(verticalAlign),
      ...distributeStyles(distribute)
    }
    const reverseLevel = applyInheritance([xsReverse, smReverse, mdReverse, lgReverse, xlReverse])
    const stylesByViewport = {
      xs: {
        flexDirection: reverseLevel[0] ? 'row-reverse' : 'row',
        flexWrap: reverseLevel[0] ? 'wrap-reverse' : 'wrap'
      },
      sm: {
        flexDirection: reverseLevel[1] ? 'row-reverse' : 'row',
        flexWrap: reverseLevel[1] ? 'wrap-reverse' : 'wrap'
      },
      md: {
        flexDirection: reverseLevel[2] ? 'row-reverse' : 'row',
        flexWrap: reverseLevel[2] ? 'wrap-reverse' : 'wrap'
      },
      lg: {
        flexDirection: reverseLevel[3] ? 'row-reverse' : 'row',
        flexWrap: reverseLevel[3] ? 'wrap-reverse' : 'wrap'
      },
      xl: {
        flexDirection: reverseLevel[4] ? 'row-reverse' : 'row',
        flexWrap: reverseLevel[4] ? 'wrap-reverse' : 'wrap'
      }
    }

    let rowStyles
    let mediaIds

    if (enableMediaQueryStyleSheet) {
      const mediaQueryStyles = createMediaQueryStyles(stylesByViewport)
      const { ids, styles } = StyleSheet.create({
        row: {
          ...staticStyles,
          ...mediaQueryStyles
        }
      })
      rowStyles = styles.row
      mediaIds = ids.row
    } else {
      rowStyles = {
        ...staticStyles,
        ...stylesByViewport[viewport]
      }
    }

    return (
      <BaseView ref={ref} {...rest} style={rowStyles} dataSet={mediaIds && { media: mediaIds }}>
        {children}
      </BaseView>
    )
  }
)
FlexGridRow.displayName = 'FlexGridRow'

FlexGridRow.propTypes = {
  /**
   * Align columns horizontally within their row.
   */
  horizontalAlign: PropTypes.oneOf(['start', 'center', 'end']),
  /**
   * Align columns vertically within their row.
   */
  verticalAlign: PropTypes.oneOf(['top', 'middle', 'bottom']),
  /**
   * Distribute empty space around columns.
   */
  distribute: PropTypes.oneOf(['around', 'between']),
  /**
   * Choose if the item order should be reversed from the 'xs' breakpoint. When you pass in false, the order will be normal from the xs breakpoint. By default, it inherits the behaviour set by the preceding prop.
   */
  xsReverse: PropTypes.bool,
  /**
   * Choose if the item order should be reversed from the 'sm' breakpoint. When you pass in false, the order will be normal from the sm breakpoint. By default, it inherits the behaviour set by the preceding prop.
   */
  smReverse: PropTypes.bool,
  /**
   * Choose if the item order should be reversed from the 'md' breakpoint. When you pass in false, the order will be normal from the md breakpoint. By default, it inherits the behaviour set by the preceding prop.
   */
  mdReverse: PropTypes.bool,
  /**
   * Choose if the item order should be reversed from the 'lg' breakpoint. When you pass in false, the order will be normal from the lg breakpoint. By default, it inherits the behaviour set by the preceding prop.
   */
  lgReverse: PropTypes.bool,
  /**
   * Choose if the item order should be reversed from the 'xl' breakpoint. When you pass in false, the order will be normal from the xl breakpoint. By default, it inherits the behaviour set by the preceding prop.
   */
  xlReverse: PropTypes.bool,
  /**
   * Content of the row, typically `FlexGrid.Col` elements.
   */
  children: PropTypes.node.isRequired
}
