import { css, CSSProperties, keyframes } from 'glamor';
import * as React from 'react';
import { MdError } from 'react-icons/md';
import { IoMdWarning } from 'react-icons/io';
import { BsCheckCircleFill, BsFillInfoCircleFill, BsX } from 'react-icons/bs';
import { Elevation } from '../../../styles/defaults/elevation.styles';
import { FeedbackStyle, useFeedbackStyles } from './feedback.styles';
import { ThemeColors } from '../../../styles/defaults/themes.interface';
import { useApphouse } from '../../../context/useApphouse';
import { observer } from 'mobx-react';
import { Loading } from '../../../components/Loading';
import {
  FeedbackPositionOptions,
  FeedbackTypeOptions,
  FeedbackVariantType
} from '../../../models/Feedback';
import { Text } from '../../Text';
import { View } from '../../View';
import { mergeStyles } from '../../../styles/mergeStyles';

export interface FeedbackProps {
  message?: React.ReactNode;
  details?: React.ReactNode;
  variant?: FeedbackVariantType;
  open: boolean;
  onClose: () => void;
  zIndex?: number;
  styleOverwrites?: FeedbackStyle;
  type?: FeedbackTypeOptions;
  position?: FeedbackPositionOptions;
  dismissButtonLabel?: string;
  showLoader?: boolean;
}

export const Feedback: React.FC<FeedbackProps> = observer(
  ({
    message,
    details,
    onClose,
    zIndex = 1000,
    styleOverwrites,
    variant = 'regular',
    open = true,
    dismissButtonLabel,
    showLoader = false,
    position = 'bottom'
  }) => {
    const { theme } = useApphouse();
    const { tokens } = theme;
    const feedbackStyles = useFeedbackStyles({
      theme: theme,
      overwrites: styleOverwrites
    });
    const { colors } = feedbackStyles;
    if (!message) {
      return null;
    }
    const containerStyle = getContainerStyle(position);
    const iconColor = getIconColorForVariant(variant, colors);
    const textColor = getTextColorForVariant(variant, colors);
    const iconSize = tokens.iconSize.s;

    return (
      <div
        tabIndex={0}
        {...css(
          feedbackStyles.container,
          {
            color: textColor,
            backgroundColor: getBackgroundColorForVariant(variant, colors),
            alignItems: details ? 'flex-start' : 'center',
            justifyContent: details ? 'flex-start' : 'center'
          },

          Elevation.depth2,
          { zIndex },
          open ? containerStyle.open : containerStyle.closed
        )}
        data-xray="Feedback"
        data-style="container"
      >
        <View orientation="vertical" gap={0}>
          <View alignItems="center" justifyContent="center" gutters="0">
            {showLoader && <Loading styleOverwrites={feedbackStyles.spinner} />}
            {variant === 'error' && (
              <span
                {...css(
                  feedbackStyles.icon,
                  { color: iconColor },
                  feedbackStyles?.iconError
                )}
              >
                {getIconForVariant(variant, iconSize)}
              </span>
            )}
            {variant === 'warning' && (
              <span
                {...css(
                  feedbackStyles.icon,
                  { color: iconColor },
                  feedbackStyles?.iconWarning
                )}
              >
                {getIconForVariant(variant, iconSize)}
              </span>
            )}
            {variant === 'success' && (
              <span
                {...css(
                  feedbackStyles.icon,
                  { color: iconColor },
                  feedbackStyles?.iconSuccess
                )}
              >
                {getIconForVariant(variant, iconSize)}
              </span>
            )}
            <Text
              styleOverwrites={mergeStyles(feedbackStyles?.text, {
                color: textColor
              })}
              data-style="text"
            >
              {message}
            </Text>
          </View>

          <Text
            styleOverwrites={mergeStyles(feedbackStyles?.details, {
              color: textColor
            })}
            data-style="details"
          >
            {details}
          </Text>
        </View>

        <button
          onClick={() => onClose()}
          {...css(feedbackStyles?.btnClose)}
          data-style="btnClose"
        >
          {dismissButtonLabel && (
            <span {...css({ color: textColor })}>{dismissButtonLabel}</span>
          )}
          {!dismissButtonLabel && (
            <span {...css({ color: textColor })}>
              <BsX size={tokens.iconSize.m} />
            </span>
          )}
        </button>
      </div>
    );
  }
);

const OFFSET = -100;
const OFFSET_START = 30;
const getContainerStyle = (
  position: FeedbackPositionOptions
): { open: CSSProperties; closed: CSSProperties } => {
  switch (position) {
    case 'bottom': {
      const disappear = keyframes({
        '0%': { bottom: OFFSET_START },
        '100%': { bottom: OFFSET }
      });

      const appear = keyframes({
        '0%': { bottom: OFFSET },
        '100%': { bottom: OFFSET_START }
      });
      return {
        open: {
          bottom: OFFSET_START,
          animation: `${appear} 0.3s ease-in`
        },
        closed: {
          bottom: OFFSET,
          animation: `${disappear} 0.3s ease-out`
        }
      };
    }
    default: {
      // default is top
      const disappear = keyframes({
        '0%': { top: OFFSET_START },
        '100%': { top: OFFSET }
      });

      const appear = keyframes({
        '0%': { top: OFFSET },
        '100%': { top: 0 }
      });
      return {
        open: {
          top: OFFSET_START,
          animation: `${appear} 0.3s ease-in`
        },
        closed: {
          top: OFFSET,
          animation: `${disappear} 0.3s ease-out`
        }
      };
    }
  }
};

const getIconForVariant = (
  variant: FeedbackVariantType,
  iconSize: number | string
) => {
  switch (variant) {
    case 'success':
      return <BsCheckCircleFill size={iconSize} />;
    case 'warning':
      return <IoMdWarning size={iconSize} />;
    case 'error':
      return <MdError size={iconSize} />;
    default:
      return <BsFillInfoCircleFill size={iconSize} />;
  }
};
const getIconColorForVariant = (
  variant: FeedbackVariantType,
  colors: ThemeColors
) => {
  switch (variant) {
    case 'success':
      return colors.onSuccess;
    case 'warning':
      return colors.onWarning;
    case 'error':
      return colors.onError;
    default:
      return colors.onPrimary;
  }
};

const getTextColorForVariant = (
  variant: FeedbackVariantType,
  colors: ThemeColors
) => {
  switch (variant) {
    case 'info':
      return colors.onInfo;
    case 'success':
      return colors.onSuccess;
    case 'warning':
      return colors.onWarning;
    case 'error':
      return colors.onError;
    default:
      return colors.onPrimary;
  }
};

const getBackgroundColorForVariant = (
  variant: FeedbackVariantType,
  colors: ThemeColors
) => {
  switch (variant) {
    case 'info':
      return colors.info;
    case 'success':
      return colors.success;
    case 'warning':
      return colors.warning;
    case 'error':
      return colors.error;
    default:
      return colors.primary;
  }
};
