import * as React from 'react';
import clsx from 'clsx';

type RgbTuple = [number, number, number];

export type SwatchDerivedElement = HTMLInputElement;

export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
  color: RgbTuple;
  mode?: 'rgb' | 'hsl';
}

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]);
};

export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
  color,
  mode = 'rgb',
  className,
  style,
  ...etcProps
}, forwardedRef) => {
  const { id, copyColor } = useSwatchControls();
  const colorValue = `${mode}(${color.join(', ')})`;

  return (
    <span
      className={clsx(
        'inline-block align-middle',
        className,
      )}
      style={style}
    >
      <input
        {...etcProps}
        ref={forwardedRef}
        type="text"
        value={colorValue}
        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}
      >
        <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: `${mode}(${color.join(' ')})`,
            }}
          />
        </span>
        <span className="tabular-nums text-xs sr-only">
          {
            color
              .map((c) => c
                .toString()
                .padStart(4, ' ')
                .split('')
                .map((cc, j) => (
                  <span
                    key={`${cc}:${j}`}
                    className={clsx({
                      'opacity-0': cc === ' ',
                    })}
                  >
                    {j === 0 && ' '}
                    {cc === ' ' && j > 0 ? '0' : cc}
                  </span>
                ))
              )
          }
        </span>
      </label>
    </span>
  );
});

Swatch.displayName = 'Swatch';
