import { ForwardedRef, forwardRef } from 'react';

import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { assertUnreachable } from '../../utils/assertUnreachable';

import { CounterBlock, CounterBlockProps } from './components/CounterBlock';
import { CounterButton, CounterButtonProps } from './components/CounterButton';
import { CounterLink, CounterLinkProps } from './components/CounterLink';
import { CounterType } from './constants';

export type CounterProps = {
  /**
   * Determines the component modification
   * Depending on this, the component can require additional props.
   */
  type?: CounterType;
} & (
  | (CounterBlockProps & {
      type?: CounterType.Default;
    })
  | (CounterButtonProps & {
      type: CounterType.Button;
    })
  | (CounterLinkProps & {
      type: CounterType.Link;
    })
);

/**
 * Component that can be used in UI to display some counter information
 *
 * ```tsx
 * import { Counter, CounterColor, IconGlyph} from 'ui-kit';
 *
 * <Counter icon={IconGlyph.InfoSolid} label="Label" value={10} color={CounterColor.Green} />
 * ```
 *
 * ## Colors
 *
 * {@link Counter} support five colors:
 *
 * | Color                       | Example                                                    |
 * | --------------------------- | ---------------------------------------------------------- |
 * | {@link CounterColor.Blue}   | <Story id="components-counter--blue" noCanvas />   |
 * | {@link CounterColor.Green}  | <Story id="components-counter--green" noCanvas />  |
 * | {@link CounterColor.Gray}   | <Story id="components-counter--gray" noCanvas />   |
 * | {@link CounterColor.Orange} | <Story id="components-counter--orange" noCanvas /> |
 * | {@link CounterColor.Red}    | <Story id="components-counter--red" noCanvas />    |
 *
 * ### Interactive
 *
 * {@link Counter} can be represented as `<button>` or as `<a>` elements.
 *
 * #### Buttons
 *
 * {@link Counter} can be clickable.
 *
 * <Story id="components-counter--as-button" />
 *
 * ```tsx
 * import { Counter, CounterColor, IconGlyph} from 'ui-kit';
 *
 * <Counter icon={IconGlyph.InfoSolid} label="Label" value={0} color={CounterColor.Gray} type={CounterType.Button} onClick={handleClick} />
 * ```
 *
 * #### Links
 *
 * {@link Counter} can be represented as link.
 *
 * <Story id="components-counter--as-link" />
 *
 * ```tsx
 * import { Counter, CounterColor, IconGlyph} from 'ui-kit';
 *
 * <Counter icon={IconGlyph.InfoSolid} label="Label" value={0} color={CounterColor.Gray} type={CounterType.Link} to="/dashboard" />
 * ```
 */
export const Counter = forwardRef<HTMLElement, CounterProps>((props, ref) => {
  const { type = CounterType.Default, ...restProps } = props;

  switch (type) {
    case CounterType.Link: {
      const { to, icon, className, color, value, label, testId, ariaDescribedBy, ...rest } =
        restProps as CounterLinkProps;
      assertEmptyObject(rest);
      return (
        <CounterLink
          ref={ref as ForwardedRef<HTMLAnchorElement>}
          ariaDescribedBy={ariaDescribedBy}
          className={className}
          color={color}
          icon={icon}
          label={label}
          testId={testId}
          to={to}
          value={value}
        />
      );
    }
    case CounterType.Button: {
      const { onClick, disabled, className, color, value, label, icon, testId, ariaDescribedBy, ...rest } =
        restProps as CounterButtonProps;
      assertEmptyObject(rest);
      return (
        <CounterButton
          ref={ref as ForwardedRef<HTMLButtonElement>}
          ariaDescribedBy={ariaDescribedBy}
          className={className}
          color={color}
          disabled={disabled}
          icon={icon}
          label={label}
          onClick={onClick}
          testId={testId}
          value={value}
        />
      );
    }
    case CounterType.Default:
      const { icon, className, color, value, label, testId, ariaDescribedBy, ...rest } =
        restProps as CounterBlockProps;
      assertEmptyObject(rest);
      return (
        <CounterBlock
          ref={ref as ForwardedRef<HTMLDivElement>}
          ariaDescribedBy={ariaDescribedBy}
          className={className}
          color={color}
          icon={icon}
          label={label}
          testId={testId}
          value={value}
        />
      );
    /* istanbul ignore next */
    default:
      assertUnreachable(type);
  }
});
