import React from "react";
import styled, { css, FlattenSimpleInterpolation } from "styled-components";
import { theme } from "../../../css/globalStyle";
import { Flex } from "../../layout";

const sizes: { [size: string]: FlattenSimpleInterpolation } = {
  xs: css`
    padding: 0.25rem 0.5rem;
    font-size: 0.625rem;
  `,
  sm: css`
    padding: 0.5rem 0.75rem;
    font-size: 0.75rem;
  `,
  md: css`
    padding: 0.625rem 1rem;
    font-size: 0.875rem;
  `,
  lg: css`
    padding: 0.75rem 1.75rem;
    font-size: 1rem;
  `
};
export interface ButtonProps {
  type?: "button" | "submit" | "reset" | undefined; // button type
  size?: "xs" | "sm" | "md" | "lg";
  variant?: "filled" | "ghost" | "outlined" | "link";
  disabled?: boolean;
  isLoading?: boolean;
  fullWidth?: boolean;
  animated?: boolean;
  animatedStyle?: string;
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
  style?: React.CSSProperties;
  value: string;
  lowercase?: boolean;
  id?: string;
  success?: boolean;
  error?: boolean;
  warning?: boolean;
  color?: string;
  suffix?: JSX.Element | null;
  prefix?: JSX.Element | null;
  customLoader?: JSX.Element;
}

type ButtonType = ButtonProps &
  Omit<React.HTMLAttributes<HTMLButtonElement>, "prefix">;

const ButtonBaseStyle = styled.button`
  pointer-events: ${({ disabled, isLoading }: ButtonType) =>
    (disabled || isLoading) && "none"};
  opacity: ${({ disabled }) => disabled && "0.5"};
  width: ${({ fullWidth }) => (fullWidth ? "100%" : "fit-content")};
  height: fit-content;
  display: flex;
  align-items: center;
  justify-content: center;
  outline: none;
  border-radius: 5px;
  cursor: pointer;
  font-weight: 500;
  text-transform: ${({ lowercase }) =>
    lowercase ? "capitalize" : "uppercase"};
  letter-spacing: 1.25px;
  transition: box-shadow 200ms, background-color 200ms;
  box-sizing: border-box;
  line-height: 16px;
`;

const Filled = styled.button<ButtonProps>`
  border: none;
  background: ${({ color }) => theme.color[color ? color : "primary"][500]};
  color: white;

  &:hover {
    background-color: ${({ color }) =>
      theme.color[color ? color : "primary"][600]};
  }

  &:focus {
    box-shadow: ${({ color }) =>
      `${theme.shadow.input[color ? color : "primary"]}`};
    outline: none;
  }

  &:active {
    box-shadow: ${({ color }) =>
      `${theme.shadow.input[color ? color : "primary"]}`};
  }
`;

const Outlined = styled.button`
  border: ${({ color }) =>
    `1px solid ${theme.color[color ? color : "primary"][500]}`};
  background: white;
  color: ${({ color }) => theme.color[color ? color : "primary"][500]};

  &:hover {
    background: white;
    background-color: ${({ color }) =>
      `${theme.color[color ? color : "primary"][100]}`};
  }

  &:focus {
    box-shadow: ${({ color }) =>
      `${theme.shadow.input[color ? color : "primary"]}`};
  }

  &:active {
    box-shadow: ${({ color }) =>
      `${theme.shadow.input[color ? color : "primary"]}`};
  }
`;

const Ghost = styled.button`
  border: 1px solid transparent;
  background: inherit;
  color: ${({ color }) => theme.color[color ? color : "primary"][500]};

  &:hover {
    background-color: ${({ color }) =>
      `${theme.color[color ? color : "primary"][100]}`};
  }

  &:focus {
    box-shadow: ${({ color }) =>
      `${theme.shadow.input[color ? color : "primary"]}`};
  }

  &:active {
    border: ${({ color }) =>
      `1px solid ${theme.color[color ? color : "primary"][500]}`};
  }
`;

const Link = styled.button`
  background: none;
  border: none;
  color: ${({ color }) => theme.color[color ? color : "primary"][500]};

  &:hover {
    text-decoration: underline;
  }
`;

const Prefix = styled.span`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const Suffix = styled.span`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const Loader = styled.div`
  width: 20px;
  height: 20px;
  margin: 0 16px;
  border: 4px solid transparent;
  border-top-color: inherit;
  border-radius: 50%;
  animation: button-loading-spinner 1s ease infinite;

  @keyframes button-loading-spinner {
    from {
      transform: rotate(0turn);
    }

    to {
      transform: rotate(1turn);
    }
  }
`;

const Variants = {
  filled: Filled,
  ghost: Ghost,
  outlined: Outlined,
  link: Link
};

const ButtonBase = React.forwardRef<HTMLButtonElement, ButtonType>(
  (
    {
      isLoading,
      type = "button",
      value,
      lowercase = false,
      variant = "filled",
      success,
      error,
      warning,
      prefix,
      suffix,
      customLoader,
      size,
      ...rest
    },
    ref
  ) => {
    const color = success
      ? "success"
      : error
      ? "error"
      : warning
      ? "warning"
      : "";

    return (
      <ButtonBaseStyle
        as={Variants[variant]}
        type={type}
        lowercase={lowercase}
        color={color}
        ref={ref}
        {...rest}
      >
        {isLoading ? (
          customLoader ? (
            customLoader
          ) : (
            <Loader />
          )
        ) : (
          <Flex align="center" justify="center" gap={2}>
            {prefix && <Prefix>{prefix}</Prefix>}
            <>{value}</>
            {suffix && <Suffix>{suffix}</Suffix>}
          </Flex>
        )}
      </ButtonBaseStyle>
    );
  }
);

export const Button = styled(ButtonBase)`
  ${({ size = "md" }) => sizes[size]};
`;
