import React from 'react'
import PropTypes from 'prop-types'
import {
  selectSystemProps,
  useSafeLayoutEffect,
  useThemeTokens,
  getTokensPropType
} from '@telus-uds/components-base'
import throttle from 'lodash.throttle'
import styled from 'styled-components'
import { htmlAttrs } from '../utils'

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

const StyledContainer = styled.div`
  overflow: auto;
  padding-bottom: ${(props) => (props.isScrollable ? `${props.tablePaddingBottom}px` : 0)};
`

const StyledTable = styled.table`
  margin: 0;
  padding: 0;
  width: ${({ fullWidth, tableWidth }) => (fullWidth ? '100%' : `${tableWidth}px`)};
  border: ${(props) => `${props.borderWidth}px solid ${props.borderColor}`};
  border-collapse: collapse;
`

const TableContext = React.createContext({})

export const useTableContext = () => React.useContext(TableContext)

/**
 * Use `Table` to display tabular data.
 *
 * - Takes an optional `spacing` variant (compact)
 * - Available in 2 text styles (medium, small)
 * - When `Table` exceeds viewport, the first column becomes sticky, enabling horizontal scrolling
 * - Right-align prices and numbers that display decimal points
 *
 * ### Building up a `Table`
 * - Use `Table.Header` and `Table.Body` as direct children of `Table`
 * - Use `Table.SubHeading` to render an intermediate data heading row
 * - Use `Table.Row` and `Table.Cell` to build up the tabular data
 * - Use `Cell`'s `type` prop to visually mark it as a row heading (`type="rowHeading"`)
 */
const Table = ({
  children,
  spacing = 'default',
  fullWidth = true,
  text = 'medium',
  tokens,
  variant,
  ...rest
}) => {
  const themeTokens = useThemeTokens('Table', tokens, variant)
  const { tablePaddingBottom, borderColor, borderWidth } = themeTokens
  const containerRef = React.useRef()
  const tableRef = React.useRef()

  const [containerWidth, setContainerWidth] = React.useState(0)
  const [tableWidth, setTableWidth] = React.useState(0)

  useSafeLayoutEffect(() => {
    const updateDimensions = () => {
      const containerClientWidth = containerRef.current?.clientWidth
      const responsiveTableWidth = fullWidth ? containerClientWidth : tableRef.current?.clientWidth
      setContainerWidth(containerClientWidth)
      setTableWidth(responsiveTableWidth)
    }

    const throttledUpdateDimensions = throttle(updateDimensions, 100, { leading: false })

    updateDimensions()

    // a pretty naive way of repeating the measurement after the fonts are loaded
    window.addEventListener('load', updateDimensions)
    window.addEventListener('resize', throttledUpdateDimensions)

    return () => {
      window.removeEventListener('load', updateDimensions)
      window.removeEventListener('resize', throttledUpdateDimensions)
    }
  }, [])

  const isScrollable = tableWidth > containerWidth
  return (
    <StyledContainer
      ref={containerRef}
      isScrollable={isScrollable}
      tablePaddingBottom={tablePaddingBottom}
    >
      <TableContext.Provider
        value={{
          text,
          isScrollable,
          tokens,
          spacing,
          variant,
          themeTokens
        }}
      >
        <StyledTable
          borderColor={borderColor}
          borderWidth={borderWidth}
          tableWidth={tableWidth}
          cellSpacing={0}
          ref={tableRef}
          fullWidth={fullWidth}
          {...selectProps(rest)}
        >
          {children}
        </StyledTable>
      </TableContext.Provider>
    </StyledContainer>
  )
}

Table.propTypes = {
  ...selectedSystemPropTypes,
  tokens: getTokensPropType('Table'),
  children: PropTypes.node,
  /**
   * Sets text style
   */
  text: PropTypes.oneOf(['medium', 'small'])
}

export default Table
