import type { ReactNativeStyle } from '@emotion/native';
import styled from '@emotion/native';
import type { Theme } from '@emotion/react';
import { TouchableHighlight, View } from 'react-native';
import { scale } from '../../utils/scale';
import Icon from '../Icon';
import Typography from '../Typography';
import {
  transformKebabCaseToCamelCase,
  type CamelCase,
} from '../../utils/helpers';

type Intent = 'primary' | 'secondary' | 'danger' | 'white' | 'inverted';

type ThemeVariant =
  | 'filled-primary'
  | 'filled-secondary'
  | 'filled-danger'
  | 'filled-white'
  | 'filled-inverted'
  | 'outlined-primary'
  | 'outlined-secondary'
  | 'outlined-danger'
  | 'outlined-white'
  | 'outlined-inverted'
  | 'text-primary'
  | 'text-secondary'
  | 'text-danger'
  | 'text-white'
  | 'text-inverted';

const getButtonSize = (themeIsCompact: boolean, themeIsMedium?: boolean) => {
  if (themeIsCompact) return scale(36);

  if (themeIsMedium) return scale(48);

  return scale(48);
};

const getTextButtonPaddingVertical = (
  theme: Theme,
  themeInlineText: boolean,
  themeIsCompact: boolean
) => {
  if (themeInlineText) {
    return 0;
  }
  if (themeIsCompact) {
    return theme.__hd__.button.space.compact.buttonPaddingVertical;
  }
  return theme.__hd__.button.space.default.textButtonPadding;
};

const getTextButtonPaddingHorizontal = (
  theme: Theme,
  themeInlineText: boolean,
  themeIsCompact: boolean
) => {
  if (themeInlineText) {
    return 0;
  }
  if (themeIsCompact) {
    return theme.__hd__.button.space.compact.buttonPaddingHorizontal;
  }
  return theme.__hd__.button.space.default.textButtonPadding;
};

const genDisabledStyles = (disabled: boolean, loading: boolean) => {
  if (!disabled || loading) return;

  return { opacity: 0.25 };
};

const genFilledContainerStyles = (
  theme: Theme,
  intent: Capitalize<Intent>,
  loading: boolean,
  compact: boolean,
  medium: boolean,
  iconOnly: boolean
): ReactNativeStyle => {
  const backgroundColorStyling = () => {
    const colorKey = `filled${intent}` as const;
    if (loading) {
      return {
        backgroundColor: theme.__hd__.button.colors.pressedBackground[colorKey],
      };
    }

    return {
      backgroundColor: theme.__hd__.button.colors.background[colorKey],
    };
  };

  const paddingStyling = (): ReactNativeStyle => {
    if (iconOnly)
      return {
        alignSelf: 'flex-start',
        width: getButtonSize(compact, medium),
        borderRadius: theme.__hd__.button.radii.rounded,
      };

    if (compact)
      return {
        alignSelf: 'flex-start',
        paddingVertical:
          theme.__hd__.button.space.compact.buttonPaddingVertical,
        paddingHorizontal: theme.__hd__.button.space.default.buttonPadding,
        borderRadius: theme.__hd__.button.radii.default,
      };

    if (medium) {
      return {
        alignSelf: 'flex-start',
        borderRadius: theme.__hd__.button.radii.default,
        paddingHorizontal: theme.__hd__.button.space.medium.buttonPadding,
      };
    }

    return {
      alignSelf: 'stretch',
      paddingHorizontal: theme.__hd__.button.space.default.buttonPadding,
      borderRadius: theme.__hd__.button.radii.default,
    };
  };

  return {
    height: getButtonSize(compact, medium),
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    ...paddingStyling(),
    ...backgroundColorStyling(),
  };
};

const genOutlineContainerStyles = (
  theme: Theme,
  intent: Capitalize<Intent>,
  loading: boolean,
  compact: boolean,
  medium: boolean,
  iconOnly: boolean
): ReactNativeStyle => {
  const borderColorStyling = () => {
    const colorKey = `outlined${intent}` as const;
    if (loading) {
      return {
        borderColor: theme.__hd__.button.colors.border[colorKey],
        backgroundColor: theme.__hd__.button.colors.pressedBackground[colorKey],
      };
    }

    return { borderColor: theme.__hd__.button.colors.border[colorKey] };
  };

  const paddingStyling = (): ReactNativeStyle => {
    if (iconOnly)
      return {
        alignSelf: 'flex-start',
        width: getButtonSize(compact, medium),
        borderRadius: theme.__hd__.button.radii.rounded,
      };

    if (compact)
      return {
        alignSelf: 'flex-start',
        paddingVertical:
          theme.__hd__.button.space.compact.buttonPaddingVertical -
          theme.__hd__.button.borderWidth.default,
        paddingHorizontal:
          theme.__hd__.button.space.default.buttonPadding -
          theme.__hd__.button.borderWidth.default,
        borderRadius: theme.__hd__.button.radii.default,
      };

    if (medium) {
      return {
        alignSelf: 'flex-start',
        borderRadius: theme.__hd__.button.radii.default,
        paddingHorizontal:
          theme.__hd__.button.space.medium.buttonPaddingHorizontal -
          theme.__hd__.button.borderWidth.default,
      };
    }

    return {
      alignSelf: 'stretch',
      paddingHorizontal:
        theme.__hd__.button.space.default.buttonPadding -
        theme.__hd__.button.borderWidth.default,
      borderRadius: theme.__hd__.button.radii.default,
    };
  };

  return {
    height: getButtonSize(compact, medium),
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    ...paddingStyling(),
    borderWidth: theme.__hd__.button.borderWidth.default,
    backgroundColor: 'transparent',
    ...borderColorStyling(),
  };
};

const getTextContainerStyles = (
  theme: Theme,
  intent: Capitalize<Intent>,
  loading: boolean,
  inlineText: boolean,
  compact: boolean,
  medium: boolean,
  iconOnly: boolean
): ReactNativeStyle => {
  const colorKey = `text${intent}` as const;

  const paddingStyles = (): ReactNativeStyle => {
    if (iconOnly) {
      return {
        alignSelf: 'flex-start',
        borderRadius: theme.__hd__.button.radii.rounded,
        width: inlineText ? undefined : getButtonSize(compact, medium),
      };
    }

    if (compact) {
      return {
        alignSelf: 'flex-start',
        paddingVertical: getTextButtonPaddingVertical(
          theme,
          inlineText,
          compact
        ),
        paddingHorizontal: getTextButtonPaddingHorizontal(
          theme,
          inlineText,
          compact
        ),
      };
    }

    if (medium) {
      return {
        alignSelf: 'flex-start',
        paddingHorizontal: inlineText
          ? 0
          : theme.__hd__.button.space.medium.textButtonPadding,
      };
    }

    return {
      paddingHorizontal: inlineText
        ? 0
        : theme.__hd__.button.space.default.textButtonPadding,
    };
  };

  return {
    height: inlineText ? undefined : getButtonSize(compact, medium),
    borderRadius: theme.__hd__.button.radii.rounded,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor:
      !inlineText && loading
        ? theme.__hd__.button.colors.pressedBackground[colorKey]
        : 'transparent',
    borderWidth: 0,
    ...paddingStyles(),
  };
};

const genTextStyles = (
  theme: Theme,
  themeButtonVariant: CamelCase<ThemeVariant>,
  intent?: Capitalize<Intent>,
  isPressed?: boolean
): ReactNativeStyle => {
  if (isPressed && intent) {
    const colorKey = `inlineText${intent}` as const;

    return {
      color: theme.__hd__.button.colors.pressedText[colorKey],
    };
  }

  return {
    color: theme.__hd__.button.colors.text[themeButtonVariant],
  };
};

const StyledButtonContainer = styled(TouchableHighlight)<{
  disabled?: boolean;
  themeButtonVariant: ThemeVariant;
  loading?: boolean;
  themeInlineText?: boolean;
  themeIsCompact?: boolean;
  themeIsMedium?: boolean;
  themeIsIconOnly?: boolean;
}>(
  ({
    disabled = false,
    loading = false,
    themeButtonVariant,
    themeInlineText = false,
    theme,
    themeIsCompact = false,
    themeIsMedium = false,
    themeIsIconOnly = false,
  }) => {
    switch (themeButtonVariant) {
      case 'filled-primary':
        return {
          ...genFilledContainerStyles(
            theme,
            'Primary',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'filled-secondary':
        return {
          ...genFilledContainerStyles(
            theme,
            'Secondary',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'filled-danger':
        return {
          ...genFilledContainerStyles(
            theme,
            'Danger',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'filled-white':
        return {
          ...genFilledContainerStyles(
            theme,
            'White',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'filled-inverted':
        return {
          ...genFilledContainerStyles(
            theme,
            'Inverted',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'outlined-primary':
        return {
          ...genOutlineContainerStyles(
            theme,
            'Primary',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'outlined-secondary':
        return {
          ...genOutlineContainerStyles(
            theme,
            'Secondary',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'outlined-danger':
        return {
          ...genOutlineContainerStyles(
            theme,
            'Danger',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'outlined-white':
        return {
          ...genOutlineContainerStyles(
            theme,
            'White',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };

      case 'outlined-inverted':
        return {
          ...genOutlineContainerStyles(
            theme,
            'Inverted',
            loading,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'text-primary':
        return {
          ...getTextContainerStyles(
            theme,
            'Primary',
            loading,
            themeInlineText,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'text-secondary':
        return {
          ...getTextContainerStyles(
            theme,
            'Secondary',
            loading,
            themeInlineText,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'text-danger':
        return {
          ...getTextContainerStyles(
            theme,
            'Danger',
            loading,
            themeInlineText,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'text-white':
        return {
          ...getTextContainerStyles(
            theme,
            'White',
            loading,
            themeInlineText,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
      case 'text-inverted':
        return {
          ...getTextContainerStyles(
            theme,
            'Inverted',
            loading,
            themeInlineText,
            themeIsCompact,
            themeIsMedium,
            themeIsIconOnly
          ),
          ...genDisabledStyles(disabled, loading),
        };
    }
  }
);

const StyledButtonText = styled(Typography.Title)<{
  disabled?: boolean;
  themeButtonVariant: ThemeVariant;
}>(({ themeButtonVariant, theme }) => {
  const themeStyling = () => {
    const camelCaseThemeVariant =
      transformKebabCaseToCamelCase(themeButtonVariant);

    return genTextStyles(theme, camelCaseThemeVariant);
  };
  return {
    flexShrink: 1,
    textAlign: 'center',
    textAlignVertical: 'center',
    lineHeight: theme.__hd__.button.lineHeights.buttonText,
    ...themeStyling(),
  };
});

const StyledSmallButtonText = styled(
  StyledButtonText.withComponent(Typography.Body)
)(({ theme }) => ({
  lineHeight: theme.__hd__.button.lineHeights.utilityButtonText,
}));

const StyledButtonTitleOfVariantText = styled(Typography.Body)<{
  disabled?: boolean;
  themeButtonVariant:
    | 'text-primary'
    | 'text-secondary'
    | 'text-danger'
    | 'text-white'
    | 'text-inverted';
  themeIsPressed?: boolean;
  themeIsCompact: boolean;
}>(({ themeButtonVariant, themeIsPressed, theme, themeIsCompact }) => {
  const themeStyling = () => {
    const themeVariant = transformKebabCaseToCamelCase(themeButtonVariant);
    switch (themeButtonVariant) {
      case 'text-primary':
        return genTextStyles(theme, themeVariant, 'Primary', themeIsPressed);
      case 'text-secondary':
        return genTextStyles(theme, themeVariant, 'Secondary', themeIsPressed);
      case 'text-danger':
        return genTextStyles(theme, themeVariant, 'Danger', themeIsPressed);
      case 'text-white':
        return genTextStyles(theme, themeVariant, 'White', themeIsPressed);
      case 'text-inverted':
        return genTextStyles(theme, themeVariant, 'Inverted', themeIsPressed);
    }
  };

  return {
    flexShrink: 1,
    lineHeight:
      theme.__hd__.button.lineHeights.titleOfTextVariant[
        themeIsCompact ? 'compact' : 'default'
      ],
    textAlign: 'center',
    textAlignVertical: 'center',
    ...themeStyling(),
  };
});

const StyledButtonIconWrapper = styled(View)<{
  themePosition: 'left' | 'right';
  themeIsCompact?: boolean;
  themeIsIconOnly?: boolean;
}>(({ themePosition, theme, themeIsCompact, themeIsIconOnly }) => {
  if (themeIsIconOnly) return {};

  switch (themePosition) {
    case 'left':
      return {
        paddingRight: themeIsCompact
          ? theme.__hd__.button.space.compact.iconPadding
          : theme.__hd__.button.space.default.iconPadding,
      };
    case 'right':
      return {
        paddingLeft: themeIsCompact
          ? theme.__hd__.button.space.compact.iconPadding
          : theme.__hd__.button.space.default.iconPadding,
      };
  }
});

const StyledButtonIcon = styled(Icon)<{
  disabled?: boolean;
  themeButtonVariant: ThemeVariant;
  themeIsPressed?: boolean;
  themeIsCompact?: boolean;
}>(({ themeButtonVariant, themeIsPressed, theme, themeIsCompact }) => {
  const themeStyling = () => {
    const themeVariant = transformKebabCaseToCamelCase(themeButtonVariant);

    switch (themeButtonVariant) {
      case 'filled-primary':
      case 'outlined-primary':
      case 'text-primary':
        return genTextStyles(theme, themeVariant, 'Primary', themeIsPressed);
      case 'filled-secondary':
      case 'outlined-secondary':
      case 'text-secondary':
        return genTextStyles(theme, themeVariant, 'Secondary', themeIsPressed);
      case 'filled-danger':
      case 'outlined-danger':
      case 'text-danger':
        return genTextStyles(theme, themeVariant, 'Danger', themeIsPressed);
      case 'filled-white':
      case 'outlined-white':
      case 'text-white':
        return genTextStyles(theme, themeVariant, 'White', themeIsPressed);
      case 'filled-inverted':
      case 'outlined-inverted':
      case 'text-inverted':
        return genTextStyles(theme, themeVariant, 'Inverted', themeIsPressed);
    }
  };

  return {
    fontSize: themeIsCompact
      ? theme.__hd__.button.sizes.iconSize.compact
      : theme.__hd__.button.sizes.iconSize.default,
    ...themeStyling(),
  };
});

export {
  StyledButtonContainer,
  StyledButtonIcon,
  StyledButtonIconWrapper,
  StyledButtonText,
  StyledButtonTitleOfVariantText,
  StyledSmallButtonText,
};
export type { Intent, ThemeVariant, CamelCase };
