import { cva, VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { cn, ComponentAnatomy, defineStyleAnatomy } from '../core/styling';

/* -------------------------------------------------------------------------------------------------
 * Anatomy
 * -----------------------------------------------------------------------------------------------*/

export const ButtonAnatomy = defineStyleAnatomy({
  root: cva(
    [
      'UI-Button_root',
      'shadow-sm whitespace-nowrap font-semibold rounded-[--radius]',
      'inline-flex items-center text-white transition ease-in text-center text-base justify-center',
      'focus-visible:outline-none focus-visible:ring-2 ring-offset-1 ring-offset-[--background] focus-visible:ring-[--ring]',
      'disabled:opacity-50 disabled:pointer-events-none',
    ],
    {
      variants: {
        intent: {
          primary:
            'bg-brand-500 hover:bg-brand-600 active:bg-brand-700 border border-transparent',
          'primary-outline':
            'text-[--brand] border border-[--brand] bg-transparent hover:bg-brand-500 active:bg-brand-600 active:border-transparent hover:text-white dark:hover:border-brand-500 dark:active:bg-brand-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white',
          'primary-subtle':
            'shadow-none text-[--brand] border bg-brand-50 border-transparent hover:bg-brand-100 active:bg-brand-200 dark:bg-opacity-10 dark:hover:bg-opacity-20',
          'primary-link':
            'shadow-none text-[--brand] border border-transparent bg-transparent hover:underline active:text-brand-700 dark:active:text-brand-300',
          'primary-basic':
            'shadow-none text-[--brand] border border-transparent bg-transparent hover:bg-brand-100 active:bg-brand-200 dark:hover:bg-opacity-10 dark:active:text-brand-300',

          warning:
            'bg-orange-500 hover:bg-orange-600 active:bg-orange-700 border border-transparent',
          'warning-outline':
            'text-[--orange] border border-[--orange] bg-transparent hover:bg-orange-500 active:bg-orange-600 active:border-transparent hover:text-white dark:hover:border-orange-500 dark:active:bg-orange-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white',
          'warning-subtle':
            'shadow-none text-[--orange] border bg-orange-50 border-transparent hover:bg-orange-100 active:bg-orange-200 dark:bg-opacity-10 dark:hover:bg-opacity-20',
          'warning-link':
            'shadow-none text-[--orange] border border-transparent bg-transparent hover:underline active:text-orange-700 dark:active:text-orange-300',
          'warning-basic':
            'shadow-none text-[--orange] border border-transparent bg-transparent hover:bg-orange-100 active:bg-orange-200 dark:hover:bg-opacity-10 dark:active:text-orange-300',

          success:
            'bg-green-500 hover:bg-green-600 active:bg-green-700 border border-transparent',
          'success-outline':
            'text-[--green] border border-[--green] bg-transparent hover:bg-green-500 active:bg-green-600 active:border-transparent hover:text-white dark:hover:border-green-500 dark:active:bg-green-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white',
          'success-subtle':
            'shadow-none text-[--green] border bg-green-50 border-transparent hover:bg-green-100 active:bg-green-200 dark:bg-opacity-10 dark:hover:bg-opacity-20',
          'success-link':
            'shadow-none text-[--green] border border-transparent bg-transparent hover:underline active:text-green-700 dark:active:text-green-300',
          'success-basic':
            'shadow-none text-[--green] border border-transparent bg-transparent hover:bg-green-100 active:bg-green-200 dark:hover:bg-opacity-10 dark:active:text-green-300',

          alert:
            'bg-red-500 hover:bg-red-600 active:bg-red-700 border border-transparent',
          'alert-outline':
            'text-[--red] border border-[--red] bg-transparent hover:bg-red-500 active:bg-red-600 active:border-transparent hover:text-white dark:hover:border-red-500 dark:active:bg-red-600 dark:hover:text-white dark:active:border-transparent dark:active:text-white',
          'alert-subtle':
            'shadow-none text-[--red] border bg-red-50 border-transparent hover:bg-red-100 active:bg-red-200 dark:bg-opacity-10 dark:hover:bg-opacity-20',
          'alert-link':
            'shadow-none text-[--red] border border-transparent bg-transparent hover:underline active:text-red-700 dark:active:text-red-300',
          'alert-basic':
            'shadow-none text-[--red] border border-transparent bg-transparent hover:bg-red-100 active:bg-red-200 dark:hover:bg-opacity-10 dark:active:text-red-300',

          gray: 'bg-gray-500 hover:bg-gray-600 active:bg-gray-700 border border-transparent',
          'gray-outline':
            'text-gray-600 border  bg-transparent hover:bg-gray-100 active:border-transparent active:bg-gray-200 dark:text-gray-300 dark: dark:hover:bg-gray-800 dark:hover:bg-opacity-50 dark:active:bg-gray-700 dark:active:border-transparent dark:hover:text-gray-100',
          'gray-subtle':
            'shadow-none text-[--gray] border bg-gray-100 border-transparent hover:bg-gray-200 active:bg-gray-300 dark:text-gray-300 dark:bg-opacity-10 dark:hover:bg-opacity-20',
          'gray-link':
            'shadow-none text-[--gray] border border-transparent bg-transparent hover:underline active:text-gray-700 dark:text-gray-300 dark:active:text-gray-200',
          'gray-basic':
            'shadow-none text-[--gray] border border-transparent bg-transparent hover:bg-gray-100 active:bg-gray-200 dark:active:bg-opacity-20 dark:text-gray-200 dark:hover:bg-opacity-10 dark:active:text-gray-200',

          white:
            'text-[#000] bg-white hover:bg-gray-200 active:bg-gray-300 border border-transparent',
          'white-outline':
            'text-white border border-gray-200 bg-transparent hover:bg-white hover:text-black active:bg-gray-100 active:text-[#000]',
          'white-subtle':
            'shadow-none text-white bg-white bg-opacity-15 hover:bg-opacity-20 border border-transparent active:bg-opacity-25',
          'white-link':
            'shadow-none text-white border border-transparent bg-transparent hover:underline active:text-gray-200',
          'white-basic':
            'shadow-none text-white border border-transparent bg-transparent hover:bg-white hover:bg-opacity-15 active:bg-opacity-20 active:text-white-300',
        },
        rounded: {
          true: 'rounded-full',
          false: null,
        },
        contentWidth: {
          true: 'w-fit',
          false: null,
        },
        size: {
          xs: 'text-sm h-6 px-2',
          sm: 'text-sm h-8 px-3',
          md: 'text-sm h-10 px-4',
          lg: 'h-12 px-6 text-lg',
          xl: 'text-2xl h-14 px-8',
        },
      },
      defaultVariants: {
        intent: 'primary',
        size: 'md',
      },
    }
  ),
  icon: cva(['UI-Button__icon', 'inline-flex self-center flex-shrink-0']),
});

/* -------------------------------------------------------------------------------------------------
 * Button
 * -----------------------------------------------------------------------------------------------*/

export type ButtonProps = React.ComponentPropsWithoutRef<'button'> &
  VariantProps<typeof ButtonAnatomy.root> &
  ComponentAnatomy<typeof ButtonAnatomy> & {
    loading?: boolean;
    leftIcon?: React.ReactNode;
    rightIcon?: React.ReactNode;
    iconSpacing?: React.CSSProperties['marginInline'];
    hideTextOnSmallScreen?: boolean;
    hideTextOnLargeScreen?: boolean;
  };

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  (props, ref) => {
    const {
      children,
      size,
      className,
      rounded = false,
      contentWidth = false,
      intent,
      leftIcon,
      rightIcon,
      iconSpacing = '0.5rem',
      loading,
      iconClass,
      disabled,
      hideTextOnSmallScreen,
      hideTextOnLargeScreen,
      ...rest
    } = props;

    return (
      <button
        type="button"
        className={cn(
          ButtonAnatomy.root({
            size,
            intent,
            rounded,
            contentWidth,
          }),
          className
        )}
        disabled={disabled || loading}
        aria-disabled={disabled}
        {...rest}
        ref={ref}
      >
        {loading ? (
          <>
            <svg
              width="15"
              height="15"
              fill="currentColor"
              className="animate-spin"
              viewBox="0 0 1792 1792"
              xmlns="http://www.w3.org/2000/svg"
              style={{
                marginInlineEnd: !hideTextOnSmallScreen ? iconSpacing : 0,
              }}
            >
              <path d="M526 1394q0 53-37.5 90.5t-90.5 37.5q-52 0-90-38t-38-90q0-53 37.5-90.5t90.5-37.5 90.5 37.5 37.5 90.5zm498 206q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-704-704q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm1202 498q0 52-38 90t-90 38q-53 0-90.5-37.5t-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-964-996q0 66-47 113t-113 47-113-47-47-113 47-113 113-47 113 47 47 113zm1170 498q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm-640-704q0 80-56 136t-136 56-136-56-56-136 56-136 136-56 136 56 56 136zm530 206q0 93-66 158.5t-158 65.5q-93 0-158.5-65.5t-65.5-158.5q0-92 65.5-158t158.5-66q92 0 158 66t66 158z"></path>
            </svg>
            {children}
          </>
        ) : (
          <>
            {leftIcon && (
              <span
                className={cn(ButtonAnatomy.icon(), iconClass)}
                style={{
                  marginInlineEnd: !hideTextOnSmallScreen ? iconSpacing : 0,
                }}
              >
                {leftIcon}
              </span>
            )}
            <span
              className={cn(
                hideTextOnSmallScreen &&
                  cn(
                    'hidden',
                    leftIcon && 'pl-[0.5rem]',
                    rightIcon && 'pr-[0.5rem]'
                  ),
                hideTextOnLargeScreen
                  ? 'inline-block lg:hidden'
                  : 'md:inline-block'
              )}
            >
              {children}
            </span>
            {rightIcon && (
              <span
                className={cn(ButtonAnatomy.icon(), iconClass)}
                style={{
                  marginInlineStart: !hideTextOnSmallScreen ? iconSpacing : 0,
                }}
              >
                {rightIcon}
              </span>
            )}
          </>
        )}
      </button>
    );
  }
);

Button.displayName = 'Button';
