import React from 'react';
import { FieldPath, FieldValues, useController, UseControllerProps } from 'react-hook-form';
import {
	Autocomplete,
	AutocompleteChangeDetails,
	AutocompleteChangeReason,
	AutocompleteProps,
	AutocompleteRenderInputParams,
	AutocompleteValue,
	ChipTypeMap,
	TextField,
	TextFieldProps
} from '@mui/material';
import { isBoolean, isEqual, isFunction, isString } from 'lodash';

import { useDefaultProps } from '../../hooks';
import { useLocalization } from '../../localization';

export type RHFAutocompleteProps<
	TFieldValues extends FieldValues,
	TName extends FieldPath<TFieldValues>,
	TValue,
	TMultiple extends boolean | undefined,
	TDisableClearable extends boolean | undefined,
	TFreeSolo extends boolean | undefined,
	TChipComponent extends React.ElementType
> = Omit<
	AutocompleteProps<TValue, TMultiple, TDisableClearable, TFreeSolo, TChipComponent>,
	'name' | 'defaultValue' | 'onChange' | 'value' | 'disabled' | 'renderInput' | 'open' | 'onOpen' | 'onClose'
> & {
	onChange?: (value: AutocompleteValue<TValue, TMultiple, TDisableClearable, TFreeSolo>) => void;
	transform?: (
		event: React.SyntheticEvent,
		value: AutocompleteValue<TValue, TMultiple, TDisableClearable, TFreeSolo>,
		reason: AutocompleteChangeReason,
		details?: AutocompleteChangeDetails<TValue> | undefined
	) => AutocompleteValue<TValue, TMultiple, TDisableClearable, TFreeSolo>;
	label?: TextFieldProps['label'];
	helperText?: TextFieldProps['helperText'];
	variant?: TextFieldProps['variant'];
	color?: TextFieldProps['color'];
	required?: TextFieldProps['required'];
	placeholder?: TextFieldProps['placeholder'];
	TextFieldProps?: TextFieldProps | ((params: AutocompleteRenderInputParams) => TextFieldProps);
} & UseControllerProps<TFieldValues, TName>;

function RHFAutocomplete<
	TFieldValues extends FieldValues,
	TName extends FieldPath<TFieldValues>,
	TValue,
	TMultiple extends boolean | undefined = false,
	TDisableClearable extends boolean | undefined = true,
	TFreeSolo extends boolean | undefined = false,
	TChipComponent extends React.ElementType = ChipTypeMap['defaultComponent']
>(inProps: RHFAutocompleteProps<TFieldValues, TName, TValue, TMultiple, TDisableClearable, TFreeSolo, TChipComponent>) {
	const {
		/** React Hook Form */
		name,
		rules,
		control,
		disabled,
		defaultValue,
		shouldUnregister,
		/** React Hook Form */

		onChange,
		onBlur,
		multiple,
		options,

		transform,

		/** TextField Props */
		required,
		label,
		helperText,
		variant,
		TextFieldProps,
		color,
		size,
		placeholder,
		/** TextField Props */

		...props
	} = useDefaultProps({ name: 'RemateRHFAutocomplete', props: inProps });

	const { translate } = useLocalization();

	const {
		field,
		fieldState: { error }
	} = useController<TFieldValues, TName>({
		name,
		defaultValue,
		disabled,
		shouldUnregister,
		control,
		rules: rules && {
			...rules,
			required: rules?.required === true ? translate('validation.required', { label }) : rules?.required
		}
	});

	function onBlurHandler(event: React.FocusEvent<HTMLDivElement, Element>) {
		field.onBlur();
		onBlur?.(event);
	}

	return (
		<Autocomplete<TValue, TMultiple, TDisableClearable, TFreeSolo, TChipComponent>
			isOptionEqualToValue={(option, currentValue) => isEqual(option, currentValue)}
			disableClearable={true as TDisableClearable}
			noOptionsText={translate(`autocomplete.noOptionsText`)}
			loadingText={translate('autocomplete.loadingText')}
			openText={translate('autocomplete.openText')}
			closeText={translate('autocomplete.closeText')}
			openOnFocus
			color={color}
			size={size}
			{...props}
			options={options || []}
			multiple={multiple}
			renderInput={(params) => {
				const _TextFieldProps = isFunction(TextFieldProps) ? TextFieldProps(params) : { ...TextFieldProps, ...params };

				return (
					<TextField
						name={field.name}
						{..._TextFieldProps}
						inputProps={{
							..._TextFieldProps.inputProps,
							autoComplete: 'new-password'
						}}
						required={
							isBoolean(rules?.required)
								? rules.required
								: isString(rules?.required) || rules?.required?.value || required
						}
						inputRef={field.ref}
						label={label}
						variant={variant}
						error={!!error}
						helperText={error?.message || helperText}
						color={color}
						size={size}
						placeholder={placeholder}
					/>
				);
			}}
			onBlur={onBlurHandler}
			onChange={(event, value, reason, details) => {
				if (isFunction(transform)) {
					const transformedValue = transform(event, value, reason, details);

					field.onChange(transformedValue);
					onChange?.(transformedValue);
				} else {
					field.onChange(value);
					onChange?.(value);
				}
			}}
			value={(field.value ?? (multiple ? [] : null)) as any}
			disabled={field.disabled}
		/>
	);
}

declare module '@mui/material' {
	interface Components {
		RemateRHFAutocomplete?: {
			defaultProps?: Partial<RHFAutocompleteProps<FieldValues, string, any, false, true, false, React.ElementType>>;
		};
	}
}

export default RHFAutocomplete;
