import { css, CSSProperties } from 'glamor';
import { observer } from 'mobx-react';
import { AnchorHTMLAttributes, ButtonHTMLAttributes, forwardRef } from 'react';
import { StyleOverwrites } from './component.interfaces';
import { Loading } from './Loading';
import {
  BoxSizeStyles,
  ButtonStyleVariant
} from '../styles/defaults/themes.interface';
import { useApphouse } from '../context/useApphouse';
import React from 'react';
import { mergeStyles } from '../styles/mergeStyles';
import { omit } from '../utils/obj/omit';
import { merge } from '..';
import { getGutterStyles } from '../styles/getGutterStyles';

export type ButtonStyles = CSSProperties;

export interface ButtonProps
  extends ButtonHTMLAttributes<HTMLButtonElement>,
    StyleOverwrites<ButtonStyles> {
  /**
   * The variant of the styles button
   */
  variant?: keyof ButtonStyleVariant;
  /**
   * The size of the button
   * @default 'm'
   */
  size?: keyof BoxSizeStyles;
  /**
   * The content of the button
   */
  children?: React.ReactNode;
  /**
   * If true, the button will be disabled and it will display a spinner
   * @default false
   * @optional
   */
  loading?: boolean;
  /**
   * If set, the button will be rendered as an anchor tag
   * an there will be limitations on the props that can be passed
   */
  href?: string;
  /**
   * The size of the spinner
   */
  loadingSize?: number;
  'data-xray'?: string;
  'data-style'?: string;
}

/**
 * The Button Component.
 *
 * Usage:
 *
 * `npm install apphouse`
 *
 * Then import the component:
 *
 * `import { Button } from 'apphouse'`
 */
export const Button = observer(
  forwardRef((props: ButtonProps, ref: React.Ref<HTMLButtonElement>) => {
    const {
      variant = 'primary',
      children,
      styleOverwrites,
      loading = false,
      size = 'm',
      href,
      title,
      disabled = false,
      loadingSize = undefined
    } = props;
    const { theme } = useApphouse();
    const { styles } = theme;
    let localStyles: ButtonStyles = {
      color: 'inherit'
    };
    const gutterStyles = getGutterStyles(props.gutters);

    try {
      localStyles = merge(
        {},
        styles.button[variant] || {},
        styles.boxSize[size] || {},
        styleOverwrites,
        gutterStyles
      );

      if (disabled) {
        localStyles = mergeStyles<ButtonStyles>(
          localStyles,
          theme.styles.utility.disabled
        );
      }
    } catch (e) {
      console.log(e);
    }

    const buttonProps = omit(props, [
      'variant',
      'styleOverwrites',
      'loading',
      'children',
      'ref',
      'resizable'
    ]);

    const buttonRef = React.useRef<HTMLButtonElement>(null);

    if (props.href) {
      return (
        <a
          href={href}
          data-variant={variant}
          {...css(
            mergeStyles(localStyles, {
              display: 'inline-flex',
              textDecoration: 'underline',
              fontFamily: theme.tokens.fontFamily.default,
              ':hover': {
                color: localStyles.color
              },
              ':disabled': {
                color: localStyles.color
              }
            })
          )}
          {...(omit(buttonProps, [
            'loadingSize'
          ]) as AnchorHTMLAttributes<HTMLAnchorElement>)}
        >
          {children}
        </a>
      );
    }
    return (
      <button
        ref={ref || buttonRef}
        data-variant={variant}
        data-xray={props['data-xray'] || 'Button'}
        data-style={props['data-style'] || 'Button'}
        disabled={props.disabled || loading}
        onClick={(clickProps) => {
          if (!(props.disabled || loading)) {
            if (props.onClick) {
              props.onClick(clickProps);
            }

            if (props.href) {
              window.open(props.href, '_blank');
            }
          }
        }}
        title={title}
        {...css(localStyles)}
        {...omit(buttonProps, ['loadingSize'])}
      >
        {children}
        {loading === true && (
          <Loading size={getLoadingSize(loadingSize, size)} />
        )}
      </button>
    );
  })
);

const getLoadingSize = (loadingSize: number | undefined, size: string) => {
  switch (size) {
    case 'xs':
      return loadingSize || 6;
    case 's':
      return loadingSize || 10;
    default:
      return loadingSize || 15;
  }
};
