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

import { Helmet, HelmetProvider } from 'react-helmet-async'
import { isEqual } from 'lodash'

import {
  componentPropType,
  selectSystemProps,
  unpackFragment,
  withLinkRouter,
  getTokensPropType,
  useThemeTokens,
  useViewport
} from '@telus-uds/components-base'
import styled from 'styled-components'
import { htmlAttrs } from '../utils'
import Item from './Item/Item'

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

const StyledList = styled.ol({
  display: 'flex',
  flexDirection: 'row',
  flexWrap: 'wrap',
  listStyle: 'none',
  listStylePosition: 'inside',
  margin: 0,
  padding: 0,
  alignItems: 'baseline'
})

const omitProps = ({
  current,
  path,
  breadcrumbName,
  indexRoute,
  childRoutes,
  component,
  ...props
}) => props

const getBreadcrumbName = (item, params) => {
  if (!item.breadcrumbName) {
    return null
  }

  let { breadcrumbName } = item

  Object.keys(params).forEach((key) => {
    breadcrumbName = breadcrumbName.replace(`:${key}`, params[key])
  })

  return breadcrumbName
}

const getPath = (path, params, concatenatePaths, paths) => {
  let p = path
  if (concatenatePaths) {
    p = p.replace(/^\//, '')
    Object.keys(params).forEach((key) => {
      p = p.replace(`:${key}`, params[key])
    })
    if (p) {
      paths.push(p)
    }
    return `/${paths.join('/')}`
  }
  return p
}

const getItems = (items, params, concatenatePaths) => {
  const paths = []

  return items
    .filter((item) => item.path)
    .map((item, i, filteredItems) => {
      const isLast = i === filteredItems.length - 1
      const breadcrumbName = getBreadcrumbName(item, params)
      const href = getPath(item.path, params, concatenatePaths, paths)
      const { LinkRouter, linkRouterProps } = item
      return {
        breadcrumbName,
        href: item.isExpander ? '#' : href,
        current: isLast,
        LinkRouter,
        linkRouterProps,
        onPress: item.onPress,
        ...omitProps(selectProps(item))
      }
    })
}

const getStructuredData = (items, baseUrl) => {
  return items.map((item, index) => ({
    '@type': 'ListItem',
    position: index + 1,
    item: {
      '@id': `${baseUrl || ''}${item.href}`,
      name: item.breadcrumbName
    }
  }))
}

const MAX_ITEMS_ON_XS_VIEWPORT = 4

/**
 * Display a hierarchy of links, commonly used for navigation.
 */
const Breadcrumbs = React.forwardRef(
  (
    {
      baseUrl,
      children,
      linkRouterProps,
      params = {},
      tokens,
      routes,
      variant,
      LinkRouter,
      ...rest
    },
    ref
  ) => {
    // React Helmet can cause a memory leak in SSR if not properly configured.
    // Only run it in SSR if theme options tells us to.
    /* const {
    themeOptions: { enableHelmetSSR }
  } = useTheme() */
    // const isHydrating = useHydrationContext()
    // const isSSR = typeof window === 'undefined' || isHydrating
    // const hasMetadata = isSSR ? enableHelmetSSR : true
    const helmetContext = {}

    const activeRoutes = children
      ? React.Children.map(
          unpackFragment(children),
          ({ props: { href, children: breadcrumbName, ...itemRest }, ref: routeRef }) => ({
            path: href,
            breadcrumbName,
            routeRef,
            ...itemRest
          })
        )
      : routes.filter((route) => route.path && route.breadcrumbName)

    const [optionsHidden, setOptionsHidden] = React.useState(false)
    const [itemsToBeRendered, setItemsToBeRendered] = React.useState([])

    const viewport = useViewport()

    const newItems = React.useMemo(() => {
      if (viewport === 'xs' && activeRoutes.length >= MAX_ITEMS_ON_XS_VIEWPORT) {
        return [
          ...activeRoutes.slice(0, 2),
          {
            path: '#',
            breadcrumbName: '...',
            onPress: (event) => {
              event.preventDefault()
              setItemsToBeRendered(activeRoutes)
            },
            isExpander: true
          },
          activeRoutes[activeRoutes.length - 1]
        ]
      }
      return activeRoutes
    }, [viewport, activeRoutes])

    React.useEffect(() => {
      if (optionsHidden) {
        if (viewport !== 'xs' && !isEqual(itemsToBeRendered, activeRoutes)) {
          setItemsToBeRendered(activeRoutes)
        }
        return
      }

      if (viewport === 'xs' && activeRoutes.length >= MAX_ITEMS_ON_XS_VIEWPORT) {
        if (!isEqual(itemsToBeRendered, newItems)) {
          setItemsToBeRendered(newItems)
          setOptionsHidden(true)
        }
      } else if (!isEqual(itemsToBeRendered, activeRoutes)) {
        setItemsToBeRendered(activeRoutes)
      }
    }, [viewport, activeRoutes, optionsHidden, itemsToBeRendered, newItems])

    const items = getItems(
      itemsToBeRendered.length > 0 ? itemsToBeRendered : activeRoutes,
      params,
      !children
    )
    const themeTokens = useThemeTokens('Breadcrumbs', tokens, variant)

    const metadata = (
      <HelmetProvider context={helmetContext}>
        <Helmet>
          <script type="application/ld+json">
            {`
            {
            "@context": "http://schema.org",
            "@type": "BreadcrumbList",
            "itemListElement": ${JSON.stringify(getStructuredData(items, baseUrl))}
            }
          `}
          </script>
        </Helmet>
      </HelmetProvider>
    )

    return (
      <nav aria-label="Breadcrumb" ref={ref} {...selectProps(rest)}>
        <StyledList iconContainerSize={themeTokens.iconContainerSize}>
          {items.map(
            ({
              href,
              current,
              breadcrumbName,
              LinkRouter: ItemLinkRouter = LinkRouter,
              linkRouterProps: itemLinkRouterProps,
              onPress,
              ...itemRest
            }) => {
              return (
                <Item
                  {...itemRest}
                  current={current}
                  href={href}
                  tokens={tokens}
                  key={href}
                  linkRouterProps={{ ...linkRouterProps, ...itemLinkRouterProps }}
                  variant={{ ...variant, size: 'micro' }}
                  LinkRouter={ItemLinkRouter}
                  onPress={onPress}
                >
                  {breadcrumbName}
                </Item>
              )
            }
          )}
        </StyledList>
        {metadata}
      </nav>
    )
  }
)

Breadcrumbs.displayName = 'Breadcrumbs'

Breadcrumbs.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('Breadcrumbs'),
  ...withLinkRouter.propTypes,
  /**
   * Base URL used to build structured data.
   */
  baseUrl: PropTypes.string,
  /**
   * A list of Items to be used as an alternative to the `routes` prop.
   */
  children: componentPropType('Item'),
  /**
   * React Router params.
   */
  params: PropTypes.object,
  /**
   * An array of routes to be displayed as breadcrumbs.
   */
  routes: PropTypes.arrayOf(
    PropTypes.shape({
      path: PropTypes.string,
      breadcrumbName: PropTypes.string
    })
  ),
  /**
   * Variant to render.
   */
  variant: PropTypes.shape({ inverse: PropTypes.bool, light: PropTypes.bool })
}

Breadcrumbs.Item = Item

export default Breadcrumbs
