/* eslint-disable @next/next/no-img-element */
import { useCallback, useState } from 'react';
import classNames from 'classnames';
import css from 'styled-jsx/css';

import type { ReactNode } from 'react';
import type { BoxProps } from '../Box';
import type { Icon, IconProps } from './toIcon';

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

export interface BitmapIconProps extends Omit<IconProps, 'color'> {
  src?: string;
  coloring?: 'light' | 'dark' | false;
}

const BitmapIcon = withSpacing<BitmapIconProps>(
  ({ className, style, size = '2.4rem', src, opacity, testId, coloring }) => {
    const [loaded, setLoaded] = useState(false);

    return (
      <div
        data-testid={testId}
        className={classNames('bitmapIcon', className, coloring)}
        style={{
          width: size,
          height: size,
          padding: `calc(${size} * 0.02)`,
          opacity,
          ...style,
        }}
      >
        <img
          src={src}
          alt=""
          // only load when in viewport
          loading="lazy"
          onLoad={useCallback(() => {
            setLoaded(true);
          }, [])}
          // prevent native image dragging interfering with our own drag-n-drop
          draggable={false}
          style={{
            width: '100%',
            height: '100%',
            opacity: loaded ? 1 : 0,
          }}
        />
        <style jsx>{`
          div.dark {
            filter: grayscale(1) brightness(0%);
          }

          div.light {
            filter: invert(1) grayscale(1) brightness(500%);
          }
        `}</style>
      </div>
    );
  }
);

interface BitmapIconHoverTargetProps extends BoxProps {
  children: ReactNode;
  enabled?: boolean;
}

const styles = css.resolve`
  .enabled:hover :global(.bitmapIcon) {
    filter: none;
  }
`;

/**
 * A simple declarative way to define a parent hover target
 * to show the colored icon. Used in <CustomBrandForm>.
 */
export const BitmapIconHoverTarget = ({
  children,
  enabled = true,
  ...boxProps
}: BitmapIconHoverTargetProps) => {
  return (
    <Box {...boxProps} className={classNames(styles.className, { enabled })}>
      {children}
      {styles.styles}
    </Box>
  );
};

/**
 * A central place to create `BitmapIcon` with an explicit `src`.
 *
 * We keep `BitmapIcon` private to enforce all variants to
 * be created via this factory. This ensures that they have
 * the static props that are required in various parts of
 * the app at point of render.
 */
export const toBitmapIcon = ({
  dynamicColoring,
  src,
}: {
  dynamicColoring: boolean | undefined;
  src: string;
}): Icon => {
  const PresetBitmapIcon: Icon = ({ coloring, ...props }) => (
    <BitmapIcon
      {...props}
      src={src}
      // only apply the `coloring` prop when dynamicColoring is true
      coloring={dynamicColoring && coloring}
    />
  );

  // set static flags that can be used elsewhere in the app
  // at render to apply conditional styling
  PresetBitmapIcon.isBitmap = true;
  PresetBitmapIcon.dynamicColoring = dynamicColoring;

  return PresetBitmapIcon;
};
