import React from 'react'
import PropTypes from 'prop-types'
import { Typography, useThemeTokens, applyShadowToken } from '@telus-uds/components-base'
import styled, { css } from 'styled-components'
import { useTableContext } from './Table'

const HEADER_TYPE = {
  HEADING: 'heading',
  SUBHEADING: 'subHeading',
  ROWHEADING: 'rowHeading'
}

const stickyStyles = ({ cellStickyShadow, stickyBackgroundColor, type }) => css`
  position: sticky;
  left: 0; // needed for sticky to work
  z-index: 2;
  clip-path: inset(0 -8px 0 0); // use clip path to cut off the shadow rendered below
  // Override default cell background with stickyBackgroundColor with an exception to subheading and heading
  ${type !== HEADER_TYPE.SUBHEADING && type !== HEADER_TYPE.HEADING
    ? `background-color: ${stickyBackgroundColor};`
    : undefined}
  &::before {
    // use a pseudo element for the sticky shadow, since we already use shadows for inner cells border
    content: '';
    box-shadow: ${cellStickyShadow};
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
  }
`
const sharedStyles = css`
  ${({
    $isSticky,
    $align,
    $cellPaddingTop,
    $cellPaddingRight,
    $cellPaddingBottom,
    $cellPaddingLeft,
    $cellBorderWidth,
    $cellBorderColor,
    $cellBorderTopWidth,
    $cellMinWidth,
    $cellBackground,
    $cellStickyShadow,
    $stickyBackgroundColor,
    $cellBottomLeftBorderRadius,
    $cellBottomRightBorderRadius,
    $cellTopLeftBorderRadius,
    $cellTopRightBorderRadius,
    $type
  }) => css`
    text-align: ${$align};
    min-width: ${$cellMinWidth}px;
    padding: ${$cellPaddingTop}px ${$cellPaddingRight}px ${$cellPaddingBottom}px
      ${$cellPaddingLeft}px;
    background-color: ${$cellBackground};
    ${$isSticky &&
    stickyStyles({
      type: $type,
      cellStickyShadow: $cellStickyShadow,
      stickyBackgroundColor: $stickyBackgroundColor
    })};
    border-style: ${$cellBorderWidth || $cellBorderTopWidth ? 'solid' : 'none'};
    border-color: ${$cellBorderColor};
    border-width: ${$cellBorderWidth}px;
    border-top-width: ${$cellBorderTopWidth || $cellBorderWidth}px;
    border-bottom-left-radius: ${$cellBottomLeftBorderRadius}px;
    border-bottom-right-radius: ${$cellBottomRightBorderRadius}px;
    border-top-left-radius: ${$cellTopLeftBorderRadius}px;
    border-top-right-radius: ${$cellTopRightBorderRadius}px;
  `}
`
const createStyledCell = (htmlElement) => styled[htmlElement]`
  ${sharedStyles};
  box-shadow: ${({ $cellBoxShadowColor, $type }) => {
    return $type === HEADER_TYPE.HEADING
      ? `inset 0 1px 0 ${$cellBoxShadowColor}, inset 0 -1px 0 ${$cellBoxShadowColor}`
      : `inset 0 1px 0 ${$cellBoxShadowColor}`
  }};
  ${({ $display }) =>
    $display &&
    `*:not(:empty) {
    display: ${$display};
  }`}
`
const StyledHeaderCell = createStyledCell('th')
const StyledDataCell = createStyledCell('td')

export const TableCell = React.forwardRef(
  ({ children, isFirstInRow, align = 'left', tokens: cellTokens, type = 'default' }, ref) => {
    const {
      text,
      isScrollable: isTableScrollable,
      tokens: tableTokens,
      spacing,
      variant
    } = useTableContext()
    const themeTokens = { ...tableTokens, ...cellTokens }

    const {
      cellMinWidth,
      cellBoxShadowColor,
      cellBackground,
      cellStickyShadow,
      cellPaddingTop,
      cellPaddingRight,
      cellPaddingLeft,
      cellPaddingBottom,
      cellBorderWidth,
      cellBorderColor,
      cellBorderTopWidth,
      cellTopLeftBorderRadius,
      cellTopRightBorderRadius,
      cellBottomLeftBorderRadius,
      cellBottomRightBorderRadius,
      fontName,
      fontWeight,
      fontSize,
      lineHeight,
      stickyBackgroundColor,
      fontColor,
      display
    } = useThemeTokens('Table', themeTokens, { spacing, type, text, ...variant })

    const sharedProps = {
      $align: align,
      $isSticky: isTableScrollable && isFirstInRow,
      $cellBackground: cellBackground,
      $cellMinWidth: cellMinWidth,
      $cellStickyShadow: applyShadowToken(cellStickyShadow).boxShadow,
      $cellPaddingTop: cellPaddingTop,
      $cellPaddingRight: cellPaddingRight,
      $cellPaddingLeft: cellPaddingLeft,
      $cellPaddingBottom: cellPaddingBottom,
      $cellBorderWidth: cellBorderWidth,
      $cellBorderColor: cellBorderColor,
      $cellBorderTopWidth: cellBorderTopWidth,
      $cellTopLeftBorderRadius: cellTopLeftBorderRadius,
      $cellTopRightBorderRadius: cellTopRightBorderRadius,
      $cellBottomLeftBorderRadius: cellBottomLeftBorderRadius,
      $cellBottomRightBorderRadius: cellBottomRightBorderRadius,
      $stickyBackgroundColor: stickyBackgroundColor,
      $cellBoxShadowColor: cellBoxShadowColor,
      $display: display,
      ref
    }

    const typographyTokens = {
      fontName,
      fontWeight,
      fontSize,
      lineHeight,
      color: fontColor
    }

    switch (type) {
      case HEADER_TYPE.HEADING:
        return (
          <StyledHeaderCell scope="col" {...sharedProps} $type={type}>
            <Typography tokens={typographyTokens}>{children}</Typography>
          </StyledHeaderCell>
        )

      case HEADER_TYPE.SUBHEADING:
        return (
          <StyledHeaderCell scope="col" {...sharedProps} $type={type}>
            <Typography tokens={typographyTokens}>{children}</Typography>
          </StyledHeaderCell>
        )

      case HEADER_TYPE.ROWHEADING:
        return (
          <StyledHeaderCell scope="row" {...sharedProps} $type={type}>
            <Typography tokens={typographyTokens}>{children}</Typography>
          </StyledHeaderCell>
        )

      default:
        return (
          <StyledDataCell {...sharedProps}>
            <Typography tokens={typographyTokens}>{children}</Typography>
          </StyledDataCell>
        )
    }
  }
)

TableCell.displayName = 'TableCell'

TableCell.propTypes = {
  type: PropTypes.oneOf(['default', 'heading', 'subHeading', 'rowHeading']),
  tokens: PropTypes.object,
  children: PropTypes.node,

  /**
   * @ignore
   * Used internally for making the first column sticky
   */
  isFirstInRow: PropTypes.bool,

  /**
   * Defines the text alignment within the cell
   */
  align: PropTypes.oneOf(['left', 'center', 'right'])
}
