import styled, {
  css,
  FlattenInterpolation,
  ThemeProps,
  DefaultTheme,
} from 'styled-components';

type Intent = 'primary' | 'danger' | 'success' | 'warning' | 'error';

type ThemeVariant =
  | 'basic'
  | 'basic-transparent'
  | 'filled-primary'
  | 'filled-danger'
  | 'filled-success'
  | 'filled-warning'
  | 'filled-error'
  | 'outlined-primary'
  | 'outlined-danger'
  | 'outlined-success'
  | 'outlined-warning'
  | 'outlined-error'
  | 'text-primary'
  | 'text-danger'
  | 'text-success'
  | 'text-warning'
  | 'text-error'
  | 'filled-reversed-primary'
  | 'filled-reversed-danger'
  | 'filled-reversed-success'
  | 'filled-reversed-warning'
  | 'filled-reversed-error';

const HOVER_COLORS = {
  primary: 'hoverPrimary',
  danger: 'hoverDanger',
  success: 'hoverSuccess',
  warning: 'hoverWarning',
  error: 'hoverError',
} as const;

const ACTIVE_COLORS = {
  primary: 'activePrimary',
  danger: 'activeDanger',
  success: 'activeSuccess',
  warning: 'activeWarning',
  error: 'activeError',
} as const;

const genFilledStyles = (
  intent: Intent
): FlattenInterpolation<ThemeProps<DefaultTheme>> => css`
  border: none;
  color: white;
  background: ${({ theme }) => theme.colors.button[intent]};
  &:hover,
  &:focus {
    background: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]};
  }
  &:active {
    background: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]};
  }
  &:disabled {
    background: ${({ theme }) => theme.colors.button.disabledBackground};
    color: ${({ theme }) => theme.colors.button.disabledText};
    cursor: not-allowed;
  }
`;

const genOutlinedStyles = (
  intent: Intent
): FlattenInterpolation<ThemeProps<DefaultTheme>> => css`
  color: ${({ theme }) => theme.colors.button[intent]};
  border-color: ${({ theme }) => theme.colors.button[intent]};
  background: transparent;
  &:hover,
  &:focus {
    color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]};
    border-color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]};
  }
  &:active {
    color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]};
    border-color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]};
  }
  &:disabled {
    color: ${({ theme }) => theme.colors.button.disabledLightText};
    border-color: ${({ theme }) => theme.colors.button.defaultBorder};
    cursor: not-allowed;
  }
`;

const genTextStyles = (
  intent: Intent
): FlattenInterpolation<ThemeProps<DefaultTheme>> => css`
  color: ${({ theme }) => theme.colors.button[intent]};
  border: none;
  background: transparent;
  min-width: unset;
  &:hover,
  &:focus {
    color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]};
  }
  &:active {
    color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]};
  }
  &:disabled {
    color: ${({ theme }) => theme.colors.button.disabledText};
    cursor: not-allowed;
  }
`;

const genFilledReversedStyles = (
  intent: Intent
): FlattenInterpolation<ThemeProps<DefaultTheme>> => css`
  border: none;
  background: white;
  color: ${({ theme }) => theme.colors.button[intent]};
  &:hover {
    opacity: 0.4;
  }
  &:focus,
  &:active {
    opacity: 0.7;
  }
  &:disabled {
    opacity: 1;
    background: ${({ theme }) => theme.colors.button.disabledBackground};
    color: ${({ theme }) => theme.colors.button.disabledText};
    cursor: not-allowed;
  }
`;

const genLoadingStyles = (variant: ThemeVariant) => {
  switch (variant) {
    case 'basic':
      return css`
        color: ${({ theme }) => theme.colors.button.activePrimary};
        border-color: ${({ theme }) => theme.colors.button.activePrimary};
      `;
    case 'basic-transparent':
    case 'filled-reversed-primary':
    case 'filled-reversed-success':
    case 'filled-reversed-warning':
    case 'filled-reversed-danger':
    case 'filled-reversed-error':
      return css`
        opacity: 0.7;
      `;
    case 'filled-primary':
      return css`
        background: ${({ theme }) => theme.colors.button.loadingPrimary};
      `;
    case 'filled-success':
      return css`
        background: ${({ theme }) => theme.colors.button.loadingSuccess};
      `;
    case 'filled-warning':
      return css`
        background: ${({ theme }) => theme.colors.button.loadingWarning};
      `;
    case 'filled-danger':
      return css`
        background: ${({ theme }) => theme.colors.button.loadingDanger};
      `;
    case 'filled-error':
      return css`
        background: ${({ theme }) => theme.colors.button.loadingError};
      `;
    case 'outlined-primary':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingPrimary};
        border-color: ${({ theme }) => theme.colors.button.loadingPrimary};
      `;
    case 'outlined-success':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingSuccess};
        border-color: ${({ theme }) => theme.colors.button.loadingSuccess};
      `;
    case 'outlined-warning':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingWarning};
        border-color: ${({ theme }) => theme.colors.button.loadingWarning};
      `;
    case 'outlined-danger':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingDanger};
        border-color: ${({ theme }) => theme.colors.button.loadingDanger};
      `;
    case 'outlined-error':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingError};
        border-color: ${({ theme }) => theme.colors.button.loadingError};
      `;
    case 'text-primary':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingPrimary};
        border-color: ${({ theme }) => theme.colors.button.loadingPrimary};
      `;
    case 'text-success':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingSuccess};
        border-color: ${({ theme }) => theme.colors.button.loadingSuccess};
      `;
    case 'text-warning':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingWarning};
        border-color: ${({ theme }) => theme.colors.button.loadingWarning};
      `;
    case 'text-danger':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingDanger};
        border-color: ${({ theme }) => theme.colors.button.loadingDanger};
      `;
    case 'text-error':
      return css`
        color: ${({ theme }) => theme.colors.button.loadingError};
        border-color: ${({ theme }) => theme.colors.button.loadingError};
      `;
  }
};

const StyledButton = styled('button').withConfig({
  shouldForwardProp: (prop, _defaultValidatorFn) =>
    !['loading', 'themeSize', 'themeVariant'].includes(prop),
})<{
  loading?: boolean;
  themeSize: 'small' | 'medium' | 'large';
  themeVariant: ThemeVariant;
}>`
  box-sizing: border-box;
  white-space: nowrap;
  line-height: 100%;
  border-style: solid;
  border-width: ${({ theme }) => theme.borderWidths.button.default};
  font-weight: ${({ theme }) => theme.fontWeights.button.text};
  margin: 0;
  cursor: pointer;

  &:focus {
    outline: none;
  }

  ${({ themeSize, theme }) => {
    switch (themeSize) {
      case 'small':
        return css`
          height: ${theme.sizes.button.small};
          padding: ${theme.space.button.smallPadding};
          font-size: ${theme.fontSizes.button.small};
          border-radius: ${theme.radii.button.small};
          min-width: ${theme.sizes.button.smallMinWidth};
        `;
      case 'medium':
        return css`
          height: ${theme.sizes.button.medium};
          padding: ${theme.space.button.mediumPadding};
          font-size: ${theme.fontSizes.button.medium};
          border-radius: ${theme.radii.button.medium};
          min-width: ${theme.sizes.button.mediumMinWidth};
        `;
      case 'large':
        return css`
          height: ${theme.sizes.button.large};
          padding: ${theme.space.button.largePadding};
          font-size: ${theme.fontSizes.button.large};
          border-radius: ${theme.radii.button.large};
          min-width: ${theme.sizes.button.largeMinWidth};
        `;
    }
  }};

  ${({ themeVariant, theme }) => {
    switch (themeVariant) {
      case 'basic':
        return css`
          color: ${theme.colors.button.defaultText};
          border-color: ${theme.colors.button.defaultBorder};
          background: ${theme.colors.button.defaultLightBackground};
          &:hover,
          &:focus {
            color: ${theme.colors.button.hoverPrimary};
            border-color: ${theme.colors.button.hoverPrimary};
          }
          &:active {
            color: ${theme.colors.button.activePrimary};
            border-color: ${theme.colors.button.activePrimary};
          }
          &:disabled {
            background: ${theme.colors.button.defaultBackground};
            color: ${theme.colors.button.disabledText};
            border-color: ${theme.colors.button.defaultBorder};
            cursor: not-allowed;
          }
        `;
      case 'basic-transparent':
        return css`
          color: ${theme.colors.button.basicTransparent};
          border-color: ${theme.colors.button.basicTransparent};
          background: transparent;
          &:hover {
            opacity: 0.4;
          }
          &:focus,
          &:active {
            opacity: 0.7;
          }
          &:disabled {
            opacity: 1;
            color: ${theme.colors.button.disabledLightText};
            border-color: ${theme.colors.button.defaultBorder};
            cursor: not-allowed;
          }
        `;
      case 'filled-primary':
        return genFilledStyles('primary');
      case 'filled-danger':
        return genFilledStyles('danger');
      case 'filled-success':
        return genFilledStyles('success');
      case 'filled-warning':
        return genFilledStyles('warning');
      case 'filled-error':
        return genFilledStyles('error');
      case 'outlined-primary':
        return genOutlinedStyles('primary');
      case 'outlined-danger':
        return genOutlinedStyles('danger');
      case 'outlined-success':
        return genOutlinedStyles('success');
      case 'outlined-warning':
        return genOutlinedStyles('warning');
      case 'outlined-error':
        return genOutlinedStyles('error');
      case 'text-primary':
        return genTextStyles('primary');
      case 'text-danger':
        return genTextStyles('danger');
      case 'text-success':
        return genTextStyles('success');
      case 'text-warning':
        return genTextStyles('warning');
      case 'text-error':
        return genTextStyles('error');
      case 'filled-reversed-primary':
        return genFilledReversedStyles('primary');
      case 'filled-reversed-danger':
        return genFilledReversedStyles('danger');
      case 'filled-reversed-success':
        return genFilledReversedStyles('success');
      case 'filled-reversed-warning':
        return genFilledReversedStyles('warning');
      case 'filled-reversed-error':
        return genFilledReversedStyles('error');
    }
  }};

  ${({ loading, themeVariant }) =>
    loading === true
      ? css`
          pointer-events: none;
          ${genLoadingStyles(themeVariant)}
        `
      : ''};
`;

const IconWrapper = styled.span<{ themePosition: 'left' | 'right' }>`
  margin: 0;
  padding: 0;
  > * {
    vertical-align: top;
  }

  ${({ themePosition, theme }) => {
    switch (themePosition) {
      case 'left':
        return css`
          padding-right: ${theme.space.button.iconPadding};
        `;
      case 'right':
        return css`
          padding-left: ${theme.space.button.iconPadding};
        `;
    }
  }};
`;

const StyledIconButton = styled.button<{
  themeSize: 'small' | 'medium' | 'large';
}>`
  display: inline-flex;
  margin: 0;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;

  &:focus,
  &:active {
    outline: none;
  }

  ${({ themeSize, theme }) => {
    switch (themeSize) {
      case 'small':
        return css`
          font-size: ${theme.fontSizes.button.small};
        `;
      case 'medium':
        return css`
          font-size: ${theme.fontSizes.button.medium};
        `;
      case 'large':
        return css`
          font-size: ${theme.fontSizes.button.large};
        `;
    }
  }};
`;

export { IconWrapper, StyledButton, StyledIconButton, Intent, ThemeVariant };
