import { useRef, useState } from "react";
import type { InputActionMeta } from "react-select";
import { components } from "react-select";

import * as S from "./style";

const Select = (props: ISelectProps): JSX.Element => {
	const {
		name,
		value,
		options,
		error,
		defaultValue,
		placeholder,
		isMulti,
		disabled,
		type,
		mandatory,
		onChange,
		alignRight,
		maxWidth,
		offSet,
	} = props;

	const className = error ? `react-select-error ${type}` : type;
	const emptyOption = { value: "", label: placeholder || "Empty" };
	const isSearchable = !(type === "inline" || type === "mini" || type === "round");

	const [hasEmptyOption, setHasEmptyOption] = useState(!mandatory);
	const [inputText, setInputText] = useState<string>("");
	const menuRef = useRef<HTMLDivElement | null>(null);

	const optionValues: IOptionProps[] = hasEmptyOption ? [emptyOption, ...options] : options;

	const handleChange = (selectedValue: unknown) => onChange((selectedValue as IOptionProps).value);

	const handleInputChange = (inputText: string, meta: InputActionMeta) => {
		if (meta.action !== "input-blur" && meta.action !== "menu-close") {
			const inputValue = inputText.replace(/\W/g, "");
			setInputText(inputText);
			setHasEmptyOption(!mandatory && inputValue.length === 0);
		}
	};

	const handleKeyDown = (e: React.KeyboardEvent) => {
		if (!menuRef.current || isSearchable) return;

		const char = e.key.toLowerCase();
		if (!/^[a-z]$/i.test(char)) return;

		const optionNodes = menuRef.current.querySelectorAll<HTMLDivElement>(".react-select__option");

		const targetNode = Array.from(optionNodes).find((node) => node.innerText.trim().toLowerCase().startsWith(char));

		if (targetNode) {
			targetNode.scrollIntoView({
				block: "nearest",
			});
		}
	};

	const getObjectValue = (value: string | undefined, options: IOptionProps[]) =>
		options.find((option) => option.value === value);

	const Menu = (menuProps: any) => (
		<div ref={menuRef}>
			<components.Menu {...menuProps} />
		</div>
	);

	return (
		<div data-testid="select-component">
			<S.StyledSelect
				name={name}
				value={getObjectValue(value, optionValues) || ""}
				options={optionValues}
				isMulti={isMulti}
				isDisabled={disabled}
				placeholder={placeholder}
				defaultValue={defaultValue}
				className={className}
				classNamePrefix="react-select"
				error={error}
				onChange={handleChange}
				isSearchable={isSearchable}
				isClearable={false}
				onInputChange={handleInputChange}
				alignRight={alignRight}
				aria-label={name}
				maxWidth={maxWidth}
				inputValue={inputText}
				components={{ Menu }}
				onKeyDown={handleKeyDown}
				offSet={offSet}
			/>
		</div>
	);
};

export interface ISelectProps {
	name: string;
	value: string | undefined;
	options: IOptionProps[];
	error?: boolean;
	disabled?: boolean;
	defaultValue?: IOptionProps;
	placeholder?: string;
	isMulti?: boolean;
	type?: string;
	mandatory?: boolean;
	alignRight?: boolean;
	onChange: (value: string) => void;
	maxWidth?: number;
	offSet?: string;
}

interface IOptionProps {
	value: string;
	label: string;
	isDisabled?: boolean;
}

export default Select;
