import { ReactHTML, ReactNode } from 'react'
import styled, { useTheme } from 'styled-components'

import Copy from './copy.js'
import Icon from './icon.js'
import IconButton from './icon-button'
import Link from './link.js'
import { PolymorphicStyledComponent } from './types.js'
import { IconName } from './icons/index.js'
import isRebrand from './is-rebrand.js'
import { CDNAsset } from './cdn-asset.js'

type Style = {
  primaryColor: string
  secondaryColor: string
  defaultIcon: IconName
  defaultActionIcon: IconName
}
const olderStyles = {
  missingInfoAction: {
    primaryColor: 'mermaidGreen500',
    secondaryColor: 'mermaidGreen100',
    defaultIcon: 'system/search',
    defaultActionIcon: 'actions/carrot-right',
  },
  improveAction: {
    primaryColor: 'bubbleBlue500',
    secondaryColor: 'bubbleBlue100',
    defaultIcon: 'actions/circle-info',
    defaultActionIcon: 'actions/carrot-right',
  },
  positiveAction: {
    primaryColor: 'seaturtleGreen200',
    secondaryColor: 'seaturtleGreen100',
    defaultIcon: 'feedback/thumbs-up',
    defaultActionIcon: 'actions/carrot-right',
  },
  neutralAction: {
    primaryColor: 'mermaidGreen400',
    secondaryColor: 'mermaidGreen100',
    defaultIcon: 'actions/circle-info',
    defaultActionIcon: 'actions/carrot-right',
  },
  warning: {
    primaryColor: 'flounderYellow200',
    secondaryColor: 'flounderYellow100',
    defaultIcon: 'actions/circle-warning',
    defaultActionIcon: 'actions/close',
  },
  error: {
    primaryColor: 'sebastianRed200',
    secondaryColor: 'sebastianRed100',
    defaultIcon: 'actions/circle-warning',
    defaultActionIcon: 'actions/close',
  },
} as const

const styles = {
  missingInfoAction: {
    primaryColor: 'navNeutral400',
    secondaryColor: 'navNeutral100',
    defaultIcon: 'system/search',
    defaultActionIcon: 'actions/carrot-right',
  },
  improveAction: {
    primaryColor: 'navPrimary400',
    secondaryColor: 'navPrimary100',
    defaultIcon: 'actions/circle-info',
    defaultActionIcon: 'actions/carrot-right',
  },
  positiveAction: {
    primaryColor: 'navStatusPositive',
    secondaryColor: 'navStatusPositive200',
    defaultIcon: 'feedback/thumbs-up',
    defaultActionIcon: 'actions/carrot-right',
  },
  neutralAction: {
    primaryColor: 'navNeutral400',
    secondaryColor: 'navNeutral100',
    defaultIcon: 'actions/circle-info',
    defaultActionIcon: 'actions/carrot-right',
  },
  warning: {
    primaryColor: 'navSecondary600',
    secondaryColor: 'navSecondary',
    defaultIcon: 'actions/circle-warning',
    defaultActionIcon: 'actions/close',
  },
  error: {
    primaryColor: 'navStatusNegative',
    secondaryColor: 'navStatusNegative200',
    defaultIcon: 'actions/circle-warning',
    defaultActionIcon: 'actions/close',
  },
} as const
// ensure styles meets required type
olderStyles as Record<string, Style>
styles as Record<string, Style>

type StyledBannerProps = {
  currentStyles: Style
  hasLabel?: boolean
  onDismiss?: () => void
  hasAction?: boolean
  shouldHideBorder?: boolean
}

export const StyledBanner = styled.aside<StyledBannerProps>`
  box-shadow: 0 10px 11px -8px rgba(0, 0, 0, 0.12);
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  text-align: center;
  padding: 16px;
  border-radius: 12px;
  overflow: hidden;
  background-color: ${({ currentStyles, theme }) => theme[currentStyles.secondaryColor]};
  cursor: ${({ hasLabel, onDismiss, hasAction }) => hasAction && !hasLabel && !onDismiss && 'pointer'};
  &::before {
    ${({ currentStyles, shouldHideBorder, theme }) =>
      !shouldHideBorder &&
      `content: '';
    width: 100%;
    height: 8px;
    position: absolute;
    left: 0;
    top: 0;
    background: ${theme[currentStyles.primaryColor]};
    border-radius: 14px 14px 0 0;`}
  }
  @media (${({ theme }) => theme.forLargerThanPhone}) {
    grid-template-rows: auto;
    grid-template-columns: auto 1fr;
    padding-right: ${({ hasLabel }) => !hasLabel && '64px'};
    text-align: left;
  }
`

export const StyledBannerAsLink = styled(StyledBanner).attrs(() => ({
  as: 'a',
}))`
  text-decoration: none;
` as PolymorphicStyledComponent<typeof StyledBanner, ReactHTML['a']>

type BannerContainerProps = {
  currentStyles: Style
  action?: () => void
  actionHref?: string
  hasLabel?: boolean
  children: ReactNode
  className?: string
  shouldHideBorder?: boolean
  ['data-testid']?: string
}

const BannerContainer = ({
  currentStyles,
  action = () => {},
  actionHref,
  hasLabel,
  children,
  className,
  shouldHideBorder,
  'data-testid': dataTestId,
}: BannerContainerProps) => {
  const sharedProps = {
    className,
    currentStyles,
    hasLabel,
    shouldHideBorder,
    'data-testid': dataTestId,
  }

  if (!hasLabel) {
    return actionHref ? (
      <StyledBannerAsLink {...sharedProps} href={actionHref}>
        {children}
      </StyledBannerAsLink>
    ) : (
      <StyledBanner {...sharedProps} onClick={action}>
        {children}
      </StyledBanner>
    )
  } else return <StyledBanner {...sharedProps}>{children}</StyledBanner>
}

export const TitleCopy = styled(Copy)`
  @media (${({ theme }) => theme.forLargerThanPhone}) {
    margin-right: 28px; /* need to give space for the (X) */
  }
`

const IconContainer = styled.div`
  flex: 0 0 24px;
  height: auto;
  @media (${({ theme }) => theme.forLargerThanPhone}) {
    margin-right: 16px;
  }
`

const Content = styled.div`
  flex: 1 1 auto;

  & > ${Copy}, & > ${Link} {
    flex: 1 1 100%;
  }
`

export const ActionIcon = styled(IconButton)<{
  currentStyles: Style
}>`
  cursor: pointer;
  position: absolute;
  right: 16px;
  top: 16px;
  width: auto;
  height: 24px;
  color: ${({ theme, currentStyles, name }) => {
    if (name === 'actions/close') {
      return isRebrand(theme) ? theme.navNeutral500 : theme.neutral500
    }
    return theme[currentStyles?.primaryColor]
  }};
  &:hover,
  &:hover:not([disabled]),
  &:hover:active,
  &:focus,
  &:focus:active,
  &:active {
    color: ${({ theme, currentStyles, name }) => {
      if (name === 'actions/close') {
        return isRebrand(theme) ? theme.navNeutral500 : theme.neutral500
      }
      return theme[currentStyles?.primaryColor]
    }};
  }
`
const ChildrenWrapper = styled.div`
  width: '100%';
`

const StyledIcon = styled(Icon)<{ currentStyles: Style }>`
  color: ${({ theme, currentStyles }) => theme[currentStyles.primaryColor]};
`

type BannerProps<T extends Record<string, Style>> = {
  action?: () => void
  actionHref?: string
  actionLabel?: ReactNode
  actionIcon?: IconName
  actionTarget?: string
  children?: ReactNode
  className?: string
  copy?: ReactNode
  expandedStyles?: T
  icon?: IconName
  onDismiss?: () => void
  shouldHideBorder?: boolean
  CDNIllustrationIcon?: string
  title?: ReactNode
  type?: keyof typeof styles & keyof T
}

export const Banner = <T extends Record<string, Style>>({
  action,
  actionHref,
  actionLabel,
  actionIcon,
  actionTarget = '',
  children,
  className,
  copy,
  expandedStyles,
  icon,
  onDismiss,
  shouldHideBorder,
  CDNIllustrationIcon: CDNAssetIcon,
  title,
  type = 'neutralAction',
}: BannerProps<T>) => {
  const hasLabel = !!actionLabel
  const hasAction = !!action || !!actionHref
  const theme = useTheme()
  const themeStyles = isRebrand(theme) ? styles : olderStyles
  const currentStyles = { ...themeStyles, ...expandedStyles }[type] ?? styles.neutralAction
  const { primaryColor, defaultIcon, defaultActionIcon } = currentStyles
  const defaultDirectory = isRebrand(theme) ? 'illustrations' : 'design-assets/illustrations'
  return (
    <BannerContainer
      currentStyles={currentStyles}
      action={action}
      actionHref={actionHref}
      hasLabel={hasLabel}
      shouldHideBorder={shouldHideBorder}
      className={className}
      data-testid={`banner:${type}`}
    >
      <IconContainer>
        {CDNAssetIcon ? (
          <CDNAsset directory={defaultDirectory} filename={CDNAssetIcon} />
        ) : (
          <StyledIcon
            name={icon || defaultIcon}
            color={primaryColor}
            currentStyles={currentStyles}
            data-testid="banner-icon"
          />
        )}
      </IconContainer>
      <Content>
        {title && <TitleCopy bold>{title}</TitleCopy>}
        {copy && <Copy>{copy}</Copy>}
        {!!children && <ChildrenWrapper>{children}</ChildrenWrapper>}
        {hasLabel && hasAction && (
          <Link bold href={actionHref} onClick={action} target={actionTarget}>
            {actionLabel}
          </Link>
        )}
      </Content>
      {!onDismiss && !hasLabel && hasAction && (
        <ActionIcon name={actionIcon || defaultActionIcon} currentStyles={currentStyles} data-testid="action-icon" />
      )}
      {onDismiss && (
        <ActionIcon
          currentStyles={currentStyles}
          onClick={onDismiss}
          data-testid="banner-dismiss"
          name="actions/close"
        />
      )}
    </BannerContainer>
  )
}

const StyledBannerExp = styled(Banner)``
export default StyledBannerExp
