import React from 'react'
import PropTypes from 'prop-types'
import {
  Link,
  selectSystemProps,
  StackView,
  Typography,
  useTheme,
  useThemeTokens,
  useResponsiveThemeTokens,
  createMediaQueryStyles,
  withLinkRouter,
  useViewport,
  getTokensPropType,
  StyleSheet
} from '@telus-uds/components-base'
import styled from 'styled-components'
import { htmlAttrs, transformGradient } from '../utils'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])

const BlockQuoteContainer = styled.blockquote`
  margin: 0;
  position: relative;
  padding-left: ${({ paddingLeft }) => `${paddingLeft}px`};
  padding-right: ${({ paddingRight }) => `${paddingRight}px`};
  padding-bottom: ${({ paddingBottom }) => `${paddingBottom}px`};
  padding-top: ${({ paddingTop }) => `${paddingTop}px`};
  &::before {
    content: '';
    left: 0;
    top: 0;
    position: absolute;
    height: 100%;
    width: ${({ width }) => `${width}px`};
    background: ${({ backgroundGradient }) =>
      backgroundGradient && transformGradient(backgroundGradient)};
  }
`

const QuoteContainer = styled.div`
  margin-bottom: ${({ marginBottom }) => `${marginBottom}px`};
`

const selectTitleHeadingTokens = (themeTokens) => ({
  fontSize: themeTokens.titleHeadingFontSize,
  fontName: themeTokens.titleHeadingFontName,
  fontWeight: themeTokens.titleHeadingFontWeight,
  lineHeight: themeTokens.titleHeadingLineHeight
})

const BlockQuote = React.forwardRef(
  (
    {
      children,
      link,
      additionalInfo,
      linkHref,
      textStyle = 'large',
      LinkRouter,
      linkRouterProps,
      tokens,
      variant,
      ...rest
    },
    ref
  ) => {
    const viewport = useViewport()
    const {
      themeOptions: { enableMediaQueryStyleSheet }
    } = useTheme()

    const useTokens = enableMediaQueryStyleSheet ? useResponsiveThemeTokens : useThemeTokens
    const resolvedTokens = useTokens(
      'BlockQuote',
      tokens,
      variant,
      !enableMediaQueryStyleSheet && { viewport }
    )
    const themeTokens = enableMediaQueryStyleSheet ? resolvedTokens[viewport] : resolvedTokens

    const {
      color,
      paddingTop,
      paddingBottom,
      paddingLeft,
      paddingRight,
      marginBottom,
      width,
      backgroundGradient,
      titleHeadingFontSize,
      titleHeadingFontName,
      titleHeadingFontWeight,
      titleHeadingLineHeight,
      titleFontSize,
      titleFontName,
      titleFontWeight,
      titleLineHeight,
      linkFontSize,
      linkFontName,
      linkFontWeight,
      linkLineHeight
    } = themeTokens

    let titleHeadingStyles
    let titleHeadingMediaIds

    if (enableMediaQueryStyleSheet) {
      const { transformedTitleHeadingThemeTokens } = Object.entries(themeTokens).reduce(
        (acc, [vp, viewportTokens]) => {
          acc.transformedTitleHeadingThemeTokens[vp] = {
            fontSize: viewportTokens.titleHeadingFontSize,
            fontName: viewportTokens.titleHeadingFontName,
            fontWeight: viewportTokens.titleHeadingFontWeight,
            lineHeight: viewportTokens.titleHeadingLineHeight
          }
          return acc
        },
        {
          transformedTitleHeadingThemeTokens: {}
        }
      )

      const titleHeadingMediaQueryStyles = createMediaQueryStyles(
        transformedTitleHeadingThemeTokens
      )

      const { ids, styles } = StyleSheet.create({
        titleHeading: {
          ...selectTitleHeadingTokens(themeTokens),
          ...titleHeadingMediaQueryStyles
        }
      })

      titleHeadingStyles = styles.titleHeading
      titleHeadingMediaIds = ids.titleHeading
    } else {
      titleHeadingStyles = {
        fontSize: titleHeadingFontSize,
        fontName: titleHeadingFontName,
        fontWeight: titleHeadingFontWeight,
        lineHeight: titleHeadingLineHeight
      }
    }

    const mappedTextSize = textStyle === 'heading' ? 'h3' : textStyle
    const titleTokens =
      textStyle === 'heading'
        ? titleHeadingStyles
        : {
            fontSize: titleFontSize,
            fontName: titleFontName,
            fontWeight: titleFontWeight,
            lineHeight: titleLineHeight
          }
    const renderLink = () => {
      if (linkHref) {
        return (
          <Link
            href={linkHref}
            tokens={{
              blockFontSize: linkFontSize,
              blockFontName: linkFontName,
              blockFontWeight: linkFontWeight,
              blockLineHeight: linkLineHeight,
              color
            }}
            variant={{ alternative: true }}
            LinkRouter={LinkRouter}
            linkRouterProps={linkRouterProps}
          >
            {link}
          </Link>
        )
      }

      return (
        <Typography
          tokens={{
            color,
            fontName: linkFontName,
            fontSize: linkFontSize,
            fontWeight: linkFontWeight,
            lineHeight: linkLineHeight
          }}
        >
          {link}
        </Typography>
      )
    }

    const renderQuote = () => {
      const quote = (
        <Typography
          tokens={{ color, ...titleTokens }}
          media={titleHeadingMediaIds}
          variant={{ size: mappedTextSize }}
        >
          {children}
        </Typography>
      )

      if (additionalInfo || link) {
        return <QuoteContainer marginBottom={marginBottom}>{quote}</QuoteContainer>
      }

      return quote
    }

    return (
      <BlockQuoteContainer
        {...selectProps(rest)}
        paddingTop={paddingTop}
        paddingBottom={paddingBottom}
        paddingLeft={paddingLeft}
        paddingRight={paddingRight}
        width={width}
        backgroundGradient={backgroundGradient}
        ref={ref}
      >
        {renderQuote()}
        {(additionalInfo || link) && (
          <StackView space={0}>
            {link && renderLink()}
            {additionalInfo && (
              <Typography tokens={{ color }} variant={{ size: 'small' }}>
                {additionalInfo}
              </Typography>
            )}
          </StackView>
        )}
      </BlockQuoteContainer>
    )
  }
)

BlockQuote.displayName = 'BlockQuote'

BlockQuote.propTypes = {
  ...selectedSystemPropTypes,
  ...withLinkRouter.propTypes,
  tokens: getTokensPropType('BlockQuote'),
  variant: PropTypes.exact({
    alternative: PropTypes.bool,
    size: PropTypes.string
  }),
  /**
   * Children nodes that can be added
   */
  children: PropTypes.node.isRequired,
  /**
   * External source's identifier (e.g. author's name)
   */
  link: PropTypes.string,
  /**
   * External source's URL
   */
  linkHref: PropTypes.string,
  /**
   * To provide additional information about the source, rendered underneath `link`
   */
  additionalInfo: PropTypes.string,
  /**
   * Whether to render BlockQuote as a heading size of `h3` or large text size
   */
  textStyle: PropTypes.oneOf(['large', 'heading'])
}

export default BlockQuote
