import * as React from 'react';
import clsx from 'clsx';
import Color from 'color';
import * as convert from 'color-convert';

/**
 * Derived HTML element of the {@link Swatch} component.
 */
export type SwatchDerivedElement = HTMLInputElement;

type ColorValue = ConstructorParameters<typeof Color>[0];

type ColorMode = keyof typeof convert;

/**
 * Props of the {@link Swatch} component.
 */
export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
  color: NonNullable<ColorValue>;
  mode?: ColorMode;
}

export const useSwatchControls = () => {
  const id = React.useId();
  const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => {
    const { value } = e.currentTarget;
    await window.navigator.clipboard.writeText(value);
  }, []);
  return React.useMemo(() => ({
    id,
    copyColor,
  }), [id, copyColor]);
};

/**
 * Component for displaying a color.
 */
export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
  // todo unify color and mode into one "value" attribute
  color,
  mode = 'rgb',
  className,
  style,
  ...etcProps
}, forwardedRef) => {
  const { id, copyColor } = useSwatchControls();
  const colorInternal = React.useMemo(() => new Color(color, mode), [color, mode]);

  const colorValue = colorInternal.hex();

  return (
    <span
      className={clsx(
        'inline-block align-middle',
        className,
      )}
      style={style}
    >
      <input
        {...etcProps}
        ref={forwardedRef}
        type="text"
        value={colorInternal.toString()}
        className="sr-only select-all peer"
        readOnly
        id={id}
        onSelect={copyColor}
      />
      <label
        className={clsx(
          'relative rounded ring-secondary/50 whitespace-nowrap inline-block align-top leading-none cursor-pointer', // todo eyedropper cursor
          'peer-focus:outline-0 peer-focus:ring-4',
          'peer-active:ring-tertiary/50',
          'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed',
        )}
        title={colorValue}
        htmlFor={id}
      >
        {/* todo border primary */}
        <span
          className="inline-block w-5 h-5 align-middle border border-[#ffffff]"
        >
          <span
            className="block w-full h-full border border-[#000000]"
            style={{
              backgroundColor: colorInternal.hex(),
            }}
          />
        </span>
        <span className="tabular-nums text-xs sr-only">
          {colorInternal.toString()}
        </span>
      </label>
    </span>
  );
});

Swatch.displayName = 'Swatch';

Swatch.defaultProps = {
  mode: 'rgb',
};
