import { useCallback, useEffect, useRef, useState } from 'react';

import type { HsvaColor, RgbaColor } from '../types';

import { equalColorObjects, hsvaToRgba, rgbaToHsva } from '../helpers';

import useEventCallback from './useEventCallback';

function useColorManipulation(
  color: RgbaColor,
  onChange: (color$: RgbaColor) => void,
): [HsvaColor, (newColor: { h?: number; s?: number; v?: number; a?: number }) => void] {
  const onChangeCallback = useEventCallback(onChange);

  const [hsva, updateHsva] = useState<HsvaColor>(() => rgbaToHsva(color));

  const cache = useRef({ color, hsva });

  useEffect(() => {
    if (!equalColorObjects(color, cache.current.color)) {
      const newHsva = rgbaToHsva(color);
      cache.current = { hsva: newHsva, color };
      updateHsva(newHsva);
    }
  }, [color]);

  useEffect(() => {
    let newColor;
    if (!equalColorObjects(hsva, cache.current.hsva)) {
      newColor = hsvaToRgba(hsva);

      if (!equalColorObjects(newColor, cache.current.color)) {
        cache.current = { hsva, color: newColor };
        onChangeCallback(newColor);
      }
    }
  }, [hsva, onChangeCallback]);

  const handleChange = useCallback(
    (params: Partial<HsvaColor>) => updateHsva((prevState) => ({ ...prevState, ...params })),
    [],
  );

  return [hsva, handleChange];
}

export default useColorManipulation;
