import { useTheme } from '@wise/components-theming';
import { clsx } from 'clsx';
import { useEffect, useState } from 'react';

import { Size, SizeExtraSmall, SizeSmall, SizeMedium, SizeLarge, SizeExtraLarge } from '../common';

// TODO: We gracefully deprecated xs, lg and xl -- remove these as part of a future breaking change to this component
type DeprecatedSize = SizeExtraSmall | SizeLarge | SizeExtraLarge;

type SizeType = SizeSmall | SizeMedium;

export type LoaderProps = {
  /**
   * @deprecated Use `size` instead.
   * @default false
   */
  small?: boolean;
  /** @default 'md' */
  size?: SizeType | DeprecatedSize;
  /** @default false */
  displayInstantly?: boolean;
  // TODO: refactor in favor of prop from `CommonProps` type
  /** @default {} */
  classNames?: Record<string, string>;
  'data-testid'?: string;
};

/**
 * Loader component
 *
 * Docs link: https://transferwise.github.io/neptune-web/components/progress/Loader
 *
 * @param root0
 * @param root0.small
 * @param root0.size
 * @param root0.classNames
 */
const Loader = ({
  small = false,
  size = Size.MEDIUM,
  displayInstantly = false,
  classNames = {},
  ...restProps
}: LoaderProps) => {
  const { theme } = useTheme();
  const [hasDebounced, setHasDebounced] = useState(displayInstantly);

  useEffect(() => {
    let cancelled: boolean;
    let timeout: ReturnType<typeof setTimeout> | undefined;

    if (!displayInstantly) {
      timeout = setTimeout(() => {
        if (!cancelled) {
          setHasDebounced(true);
        }
      }, 1000);
    }

    return () => {
      cancelled = true;

      clearTimeout(timeout);
    };
  }, []);

  const style = (className: string): string => classNames[className] || className;
  const legacySize: SizeType | DeprecatedSize = small ? Size.SMALL : size;
  const supportedSize = getSupportedSize(legacySize);

  if (theme === 'forest-green') {
    // eslint-disable-next-line no-console
    console.warn(
      'Loader is forbidden to use with Forest Green theme. Check the https://wise.design/components/screen-loader for more info.',
    );
    return <></>;
  }

  return (
    <div
      className={clsx(style('tw-loader'), style(`tw-loader--${supportedSize}`), {
        'tw-loader--visible': hasDebounced,
      })}
      data-testid={restProps['data-testid']}
    />
  );
};

const getSupportedSize = (size: SizeType | DeprecatedSize): SizeType => {
  switch (size) {
    case Size.SMALL:
    case Size.EXTRA_SMALL:
      return Size.SMALL;

    case Size.EXTRA_LARGE:
    case Size.LARGE:
    case Size.MEDIUM:
    default:
      return Size.MEDIUM;
  }
};

export default Loader;
