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

import Body from '../body';
import { Size, SizeExtraSmall, SizeSmall, SizeMedium, SizeLarge, SizeExtraLarge } from '../common';
import { Typography } from '../common/propsValues/typography';

// 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;
  /** Optional label displayed below the loader */
  label?: ReactNode;
  // 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,
  label,
  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://docs.wise.design/components/screen-loader for more info.',
    );
    return <></>;
  }

  return (
    <div className={style('tw-loader')} data-testid={restProps['data-testid']}>
      <div
        className={clsx(style('tw-loader-asset'), style(`tw-loader-asset--${supportedSize}`), {
          'tw-loader-asset--visible': hasDebounced,
        })}
      />
      {label && hasDebounced && (
        <Body type={Typography.BODY_LARGE_BOLD} as="span" className={style('text-secondary')}>
          {label}
        </Body>
      )}
    </div>
  );
};

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;
