import classNames from 'classnames';
import {
  StyleColorVariants,
  StyleColorVariantsMap,
  StyleType,
} from 'core/_variants';
import React from 'react';

type Props = {
  href?: string;
  variant?: StyleColorVariants;
  type?: StyleType;
  iconed?: boolean | "only";
  glowing?: boolean;
  disabled?: boolean;
  onClick?: (event: React.MouseEvent) => void;
  children?: React.ReactNode;
  className?: string | undefined;
  rel?: string | undefined;
  htmlType?: 'button' | 'submit' | 'reset' | undefined;
};

const buttonBgVariants: StyleColorVariantsMap<string> = {
  gray: 'bg-gray-500',
  blue: 'bg-blue-500',
  emerald: 'bg-emerald-600',
  pink: 'bg-pink-500',
  purple: 'bg-purple-500',
  red: 'bg-red-500',
  sky: 'bg-sky-500',
  yellow: 'bg-yellow-500',
  "dark-coral": "bg-dark-coral-500",
};

const buttonBgDisabledVariants: StyleColorVariantsMap<string> = {
  gray: 'bg-gray-200',
  blue: 'bg-blue-100/10',
  emerald: 'bg-emerald-200/50',
  pink: 'bg-pink-200/50',
  purple: 'bg-purple-200/50',
  red: 'bg-red-200/50',
  sky: 'bg-sky-200/50',
  yellow: 'bg-yellow-200/50',
  "dark-coral": "bg-dark-coral-200/50",
};

const buttonBgDisabledHoverVariants: StyleColorVariantsMap<string> = {
  gray: 'hover:bg-gray-500/50',
  blue: 'hover:bg-blue-100/10',
  emerald: 'hover:bg-emerald-500/50',
  pink: 'hover:bg-pink-500/50',
  purple: 'hover:bg-purple-500/50',
  red: 'hover:bg-red-500/50',
  sky: 'hover:bg-sky-500/50',
  yellow: 'hover:bg-yellow-500/50',
  "dark-coral": "hover:bg-dark-coral-500/50",
};

const buttonHoverBgVariants: StyleColorVariantsMap<string> = {
  gray:    'hover:bg-gray-600',
  blue:    'hover:bg-blue-400',
  emerald: 'hover:bg-emerald-600',
  pink:    'hover:bg-pink-600',
  purple:  'hover:bg-purple-600',
  red:     'hover:bg-red-600',
  sky:     'hover:bg-sky-600',
  yellow:  'hover:bg-yellow-600',
  "dark-coral": "hover:bg-dark-coral-600",
};

const buttonBorderVariants: StyleColorVariantsMap<string> = {
  gray: 'border-gray-500',
  blue: 'border-blue-500',
  emerald: 'border-emerald-700',
  pink: 'border-pink-300',
  purple: 'border-purple-300',
  red: 'border-red-300',
  sky: 'border-sky-300',
  yellow: 'border-yellow-300',
  "dark-coral": "border-dark-coral-500",
};

const buttonBorderHoverVariants: StyleColorVariantsMap<string> = {
  gray: 'hover:border-gray-500',
  blue: 'hover:border-blue-400',
  emerald: 'hover:border-emerald-900',
  pink: 'hover:border-pink-400',
  purple: 'hover:border-purple-400',
  red: 'hover:border-red-500',
  sky: 'hover:border-sky-400',
  yellow: 'hover:border-yellow-400',
  "dark-coral": "hover:border-dark-coral-400",
};

const buttonTextVariants: StyleColorVariantsMap<string> = {
  gray: 'text-white',
  blue: 'text-white',
  emerald: 'text-emerald-300',
  pink: 'text-white',
  purple: 'text-white',
  red: 'text-white',
  sky: 'text-white',
  yellow: 'text-white',
  "dark-coral": "text-white",
};

const buttonTextHoverVariants: StyleColorVariantsMap<string> = {
  blue: 'hover:text-white',
  emerald: 'hover:text-emerald-900',
  gray: 'hover:text-white',
  pink: 'hover:text-white',
  purple: 'hover:text-white',
  red: 'hover:text-white',
  sky: 'hover:text-white',
  yellow: 'hover:text-white',
  "dark-coral": 'hover:text-white',
}

const buttonTextMutedVariants: StyleColorVariantsMap<string> = {
  gray:    'text-gray-500',
  blue:    'text-gray-50',
  emerald: 'text-gray-50',
  pink:    'text-gray-50',
  purple:  'text-gray-50',
  red:     'text-gray-50',
  sky:     'text-gray-50',
  yellow:  'text-gray-50',
  "dark-coral": "text-gray-500",
};

const buttonGlowVariants: StyleColorVariantsMap<string> = {
  gray: 'shadow-gray-300/50',
  blue: 'shadow-blue-500/50',
  emerald: 'shadow-blue-700/50',
  pink: 'shadow-blue-300/50',
  purple: 'shadow-blue-300/50',
  red: 'shadow-blue-300/50',
  sky: 'shadow-blue-300/50',
  yellow: 'shadow-blue-300/50',
  "dark-coral": "shadow-dark-coral-300/50",
};

const buttonHoverGlowVariants: StyleColorVariantsMap<string> = {
  gray: 'hover:shadow-gray-300/50',
  blue: 'hover:shadow-blue-400/50',
  emerald: 'hover:shadow-blue-300/50',
  pink: 'hover:shadow-blue-300/50',
  purple: 'hover:shadow-blue-300/50',
  red: 'hover:shadow-blue-300/50',
  sky: 'hover:shadow-blue-300/50',
  yellow: 'hover:shadow-blue-300/50',
  "dark-coral": "hover:shadow-dark-coral-300/50",
};

const isURL = (str: string) =>
  /^(?:\w+:)?\/\/([^\s.]+\.\S{2}|localhost[:?\d]*)\S*$/.test(str);

const isInternalURL = (str: string) => /^\/(\S*\/)*\S*\/?$/.test(str);

/**
 * Common button component
 * @param {string|undefined} href New location link
 * @param {boolean} iconed Flag to process component with icon. Default: `false`
 * @param {StyleGlobalVariants|undefined} variant Button variant.
 * Default: `base`
 * @param {StyleType} type Button type.
 * Default: `fill`
 * @param {boolean|undefined} glowing Enables glowing shadow around
 * button element. Default `false`
 * @param {boolean|undefined} disabled Shows button element as
 * disabled item
 * @return {JSX.Element}
 */
const Button = ({
  href,
  iconed,
  variant = 'gray',
  type = 'fill',
  glowing = false,
  disabled,
  onClick: onPress,
  children,
  className,
  rel,
  htmlType,
}: Props) =>{
  const isExternal = isURL(href ?? '');
  const isInternal = isInternalURL(href ?? '');

  const As = isExternal || isInternal ? 'a' : 'button';

  return (
    <As
      rel={rel}
      href={href}
      type={htmlType}
      onClick={!disabled ? onPress : undefined}
      className={classNames([
        'text-center',
        'rounded-lg font-semibold',
        'transition-[box-shadow,background-color,color,border-color]',
        'border',
        {
          'px-2 py-2': iconed === "only",
          'py-3 pl-2 pr-5': iconed && iconed !== "only",
          'py-3 px-8': !iconed,
          '!cursor-default': disabled,
        },
        {
          'shadow-lg': !disabled && glowing && type !== 'text',
          'hover:shadow-lg': !disabled && glowing,
          // Text variants
          [`${buttonTextVariants[variant]}`]: !disabled,
          [`${buttonTextHoverVariants[variant]}`]: !disabled && type === "outline",
          // Background variants
          [`${buttonBgVariants[variant]}`]: !disabled && type === 'fill',
          [`${buttonHoverBgVariants[variant]}`]: !disabled,
          // Glowing variants
          [`${buttonGlowVariants[variant]}`]:
            !disabled && glowing === true && type !== 'text',
          [`${buttonHoverGlowVariants[variant]}`]: glowing,
          // Disabled variants
          [`${buttonTextMutedVariants[variant]}`]: disabled,
          [`${buttonBgDisabledVariants[variant]}`]: disabled && type === 'fill',
          [`${buttonBgDisabledHoverVariants[variant]}`]: disabled,
          // Border variants
          [`${buttonBorderVariants[variant]}`]: type !== 'text',
          '!border-transparent': disabled || type === 'text',
        },
        buttonBorderHoverVariants[variant],
        className,
      ])}
    >
      {children}
    </As>
  );
};

export default Button;
