import React, { useRef, useState, memo, useReducer, useCallback } from "react";

import { useHandleClickOutside } from "@ax/hooks";
import { IconAction } from "@ax/components";
import { defaultColors, getOptions, hex3to6 } from "./helpers";
import Picker from "./Picker";

import * as S from "./style";

const ColorPicker = (props: IProps): JSX.Element => {
	const { value, onChange, error, colors = [], handleValidation, theme, isThemePalette, disabled } = props;

	const getCurrentColors = () => {
		if (isThemePalette) {
			const currentOption = colors?.find((options: any) => options.theme === theme);
			return currentOption ? currentOption?.options : defaultColors;
		} else {
			return colors.length ? colors : defaultColors;
		}
	};

	const currentColors = getCurrentColors();

	const getInitialState = () => {
		const hexRegEx = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
		const isHexValue = hexRegEx.test(value);

		const defaultColor = currentColors[0];
		if (isThemePalette) {
			const currentValue = isHexValue ? { hex: value } : currentColors.find((color: any) => color.name === value);
			const isObject = typeof defaultColor === "object";

			let color;
			if (currentValue) {
				color = isObject ? currentValue.hex : currentValue;
			} else {
				color = isObject ? defaultColor.hex : defaultColor;
			}

			return { color, inputValue: color };
		} else {
			const color = value ? value : defaultColor;
			return { color, inputValue: color };
		}
	};

	const initialState = getInitialState();
	const reducer = useCallback((state: any, payload: any) => ({ ...state, ...payload }), []);
	const [state, dispatch] = useReducer(reducer, initialState);
	const [isVisible, setIsVisible] = useState(false);
	const wrapper = useRef<HTMLDivElement>(null);

	const handleClickOutside = (e: any) => {
		if (wrapper.current && wrapper.current.contains(e.target)) {
			return;
		}

		setIsVisible(false);
	};

	useHandleClickOutside(isVisible, handleClickOutside);

	const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
		let inputValue = e.target.value;
		dispatch({ inputValue });
		const re3 = /^#[0-9a-fA-F]{3}$/;
		const re6 = /^#[0-9a-fA-F]{6}$/;

		if (re3.test(inputValue)) {
			inputValue = hex3to6(inputValue);
			dispatch({ color: inputValue });
			onChange(inputValue);
		} else if (re6.test(inputValue)) {
			dispatch({ color: inputValue });
			onChange(inputValue);
		}
		error && handleValidation && handleValidation(inputValue, { colorHex: true });
	};

	const handlePickerChange = (value: string | any) => {
		const isObject = typeof value === "object";
		const hex = !isObject ? value : value.hex;
		const name = !isObject ? value : value.name;
		dispatch({ color: hex, inputValue: hex });
		onChange(name);
	};

	const handleOnBlur = (e: React.FocusEvent<HTMLInputElement>) => {
		handleValidation && handleValidation(e.target.value, { colorHex: true });
	};

	const togglePicker = () => setIsVisible(!isVisible);

	const icon = isVisible ? "close" : "colorPicker";

	return (
		<S.Wrapper ref={wrapper} data-testid="color-picker-wrapper">
			<S.InputWrapper>
				<S.ColorWrapper background={state.color} />
				<S.Input
					data-testid="input-picker-wrapper"
					type="text"
					value={state.inputValue}
					onChange={handleInputChange}
					error={error}
					placeholder="#FFFFFF"
					onBlur={handleOnBlur}
					disabled={disabled}
				/>
				<S.IconWrapper>
					<IconAction icon={icon} size="s" onClick={togglePicker} disabled={disabled} />
				</S.IconWrapper>
			</S.InputWrapper>
			{isVisible && (
				<Picker
					value={state.color}
					onChange={handlePickerChange}
					colors={getOptions(theme, isThemePalette, currentColors)}
				/>
			)}
		</S.Wrapper>
	);
};

export interface IProps {
	value: string;
	error?: boolean;
	colors?: string[] | Record<string, unknown>[] | any[];
	onChange: (newColor: string) => void;
	handleValidation?: (value: string, validators: Record<string, unknown>) => void;
	theme: string;
	isThemePalette?: boolean;
	disabled?: boolean;
}

export default memo(ColorPicker);
