import React from 'react';
import { GestureResponderEvent, TouchableOpacity } from 'react-native';
import {
  useRestyle,
  spacing,
  border,
  backgroundColor,
  createVariant,
  VariantProps,
  createRestyleComponent,
} from '@shopify/restyle';
import type { Theme } from '../../theme/theme';
import { Text } from '../Text';
import { Box } from '../Box';
import { useTheme } from '../../theme/ThemeProvider';
import type { theme } from '../../theme/theme';
import { Normalize } from '../../utils/normalize';
import { Spinner } from '../Spinner';

type ButtonProps = React.ComponentProps<typeof ButtonContainer> & {
  label?: string;
  type?: TypeButton;
  icon?: React.ReactNode;
  loading?: boolean;
  onPress: (event: GestureResponderEvent) => void;
};

type TypeButton = 'large' | 'medium' | 'small';

const restyleFunctions = [spacing, backgroundColor, border];

const ButtonContainer = createRestyleComponent<
  VariantProps<Theme, 'buttonVariants'> &
    React.ComponentProps<typeof Box> & {
      disabled?: boolean;
    },
  Theme
>(
  [
    createVariant({
      themeKey: 'buttonVariants',
    }),
  ],
  Box
);

const colorText: {
  [key in keyof typeof theme.buttonVariants]: keyof typeof theme.colors;
} = {
  primary: 'white',
  disabled: 'white',
  outlinedDisabled: 'gray60',
  outlined: 'darkBlueGray',
  outlinedPrimary: 'green',
  light: 'darkBlueGray',
};

const typeButton: { [key in TypeButton]: number } = {
  large: Normalize(48),
  medium: Normalize(40),
  small: Normalize(32),
};

/**
 * @onPress Called when the touch is released, but not if cancelled
 * @label Button title
 * @disabled Disable the onpress function
 * @variant Different states of the main button
 * @type Main button height 'large' | 'medium' | 'small';
 * @loading Show a loading indicator and disable the button
 * @icon Library icons phosphor-react-native
 * @see https://zeroheight.com/502cb86ad/p/281e3e-buttons/b/93e007
 */
export const Button: React.FC<ButtonProps> = ({
  onPress = () => console.warn('onPress is a required field'),
  label,
  disabled,
  variant = 'primary',
  type = 'large',
  loading = false,
  icon,
  ...rest
}) => {
  const props = useRestyle(restyleFunctions, rest);

  const { fonts } = useTheme();
  const isOutlinedDisabled = disabled && variant === 'outlined';

  const variantButton = isOutlinedDisabled
    ? 'outlinedDisabled'
    : disabled
    ? 'disabled'
    : variant;
  let textColor: keyof typeof theme.colors = 'white';

  let minHeight = typeButton.large;

  if (typeof variant !== 'object' && variant) {
    textColor = colorText[isOutlinedDisabled ? 'outlinedDisabled' : variant];
    minHeight = typeButton[type];
  }

  return (
    <TouchableOpacity onPress={onPress} disabled={loading || disabled}>
      <ButtonContainer
        variant={variantButton}
        minHeight={minHeight}
        width="100%"
        justifyContent="center"
        alignItems="center"
        flexDirection="row"
        borderRadius={Normalize(4)}
        {...props}
      >
        {loading ? (
          <Spinner
            size={type}
            variant={variant === 'outlined' ? 'secondary' : 'primary'}
          />
        ) : (
          <>
            {!!icon && <Box marginRight="spacing-xs">{icon}</Box>}
            <Text
              color={textColor}
              variant="body"
              fontFamily={fonts.caustenRoundBold}
            >
              {label}
            </Text>
          </>
        )}
      </ButtonContainer>
    </TouchableOpacity>
  );
};
