import clsx from 'clsx';
import { ComponentType, ReactNode } from 'react';
import * as lucideIcons from 'lucide-react';
import { isValidElementType } from 'react-is';

import Svg, { SvgIcons } from './Svg';

export interface IconProps {
  icon: ReactNode | ComponentType<unknown>;
}

export type IconMode =
  | 'alt'
  | 'primary'
  | 'primary-alt'
  | 'secondary'
  | 'secondary-alt'
  | 'warning'
  | 'warning-alt'
  | 'danger'
  | 'danger-alt'
  | 'success'
  | 'success-alt';

export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';

interface Props {
  icon: ReactNode | ComponentType<{ size?: string | number }>;
  className?: string;
  size?: IconSize;
  mode?: IconMode;
  spin?: boolean;
}

export function Icon({ icon, className, mode, size, spin }: Props) {
  const classes = clsx(className, 'icon inline-flex', {
    [`icon-${mode}`]: mode,
    [`icon-${size}`]: size,
    'animate-spin-slow': spin,
  });

  if (typeof icon !== 'string') {
    const Icon = isValidElementType(icon) ? icon : null;

    if (Icon) {
      return <Icon className={classes} aria-hidden="true" role="img" />;
    }

    return (
      <span className={classes} aria-hidden="true" role="img">
        {icon}
      </span>
    );
  }

  if (icon.indexOf('svg-') === 0) {
    const svgIcon = icon.replace('svg-', '');
    return (
      <Svg
        icon={svgIcon as keyof typeof SvgIcons}
        className={classes}
        aria-hidden="true"
      />
    );
  }

  const iconName = icon
    .split('-')
    .map((s) => s.slice(0, 1).toUpperCase() + s.slice(1))
    .join('') as keyof typeof lucideIcons;
  const IconComponent = lucideIcons[iconName] as React.FC<
    React.SVGProps<SVGSVGElement>
  >;
  if (!IconComponent) {
    // console error so that the error is logged but no functionality is broken
    // eslint-disable-next-line no-console
    console.error(`Icon not found: '${icon}'`);
    return null;
  }

  return <IconComponent className={classes} aria-hidden="true" />;
}