import { type CSSProperties, type FC } from 'react';

import type { WithSpacingProps } from '~/src/lib/hocs/withSpacing';
import type { ClickableProps } from '../Clickable';
import type { BitmapIconProps } from './BitmapIcon';

import withSpacing from '~/src/lib/hocs/withSpacing';
import Clickable from '../Clickable';

const TO_DEGREES = {
  up: 0,
  right: 90,
  down: 180,
  left: 270,
};

export interface IconProps
  extends WithSpacingProps,
    Omit<ClickableProps, 'children'> {
  direction?: 'up' | 'right' | 'down' | 'left';
  color?: string;
  size?: number | string;
  opacity?: number;
  className?: string;
  style?: CSSProperties;
  testId?: string;
}

export type Icon = FC<IconProps & BitmapIconProps> & {
  /**
   * Flag to indicate if the underlying icon is a bitmap (not default inline svg).
   * This is the case for 'CustomBrands' where users upload icons themselves.
   */
  isBitmap?: boolean;

  /**
   * Flag to indicate if the Icon can have 'dynamic coloring' applied.
   */
  dynamicColoring?: boolean;
};

const toIcon = (
  Content: FC<{
    style: CSSProperties;
    className?: string;
    testId?: string;
  }>,
  baseStyle?: { margin?: string }
) => {
  const Icon: Icon = ({
    direction,
    color = 'currentColor',
    size = '2.4rem',
    opacity,
    className,
    style,
    testId,
    isInline = true,
    ...clickableProps
  }) => {
    const transform = direction && `rotate(${TO_DEGREES[direction]}deg)`;

    // ensure we don't have large decimals
    size = typeof size === 'number' ? Math.round(size) : size;

    const iconStyle = {
      fill: color,
      transform,
      color,
      width: size,
      height: size,
      opacity,
      ...baseStyle,
    };

    // wrap in Clickable if needed
    if (clickableProps.onClick) {
      return (
        <Clickable
          className={className}
          style={style}
          testId={testId}
          isInline={isInline}
          {...clickableProps}
        >
          <Content style={iconStyle} />
        </Clickable>
      );
    }

    return (
      <Content
        style={{ ...iconStyle, ...style }}
        className={className}
        data-testid={testId}
      />
    );
  };

  return withSpacing(Icon) as Icon;
};

export default toIcon;
