import type React from 'react';
import type { FieldValues, UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { isBoolean, isFunction, isNumber, isRegExp, isString } from 'lodash';

import { useDefaultProps } from '../../hooks';
import { useLocalization } from '../../localization';
import { TextField, TextFieldProps } from '../text-field';

export type RHFTextFieldProps<
	T extends FieldValues = FieldValues,
	Nullable extends boolean = true,
	TransformedValue = never
> = Omit<TextFieldProps<Nullable>, 'value' | 'name' | 'disabled' | 'error' | 'onChange'> &
	UseControllerProps<T> & {
		/** Function to transform value before emitting */
		transform?: (value: Nullable extends true ? string | null : string) => TransformedValue;
		onChange?: (
			value: TransformedValue extends [never] ? (Nullable extends true ? string | null : string) : TransformedValue,
			event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
		) => void;
	};

function RHFTextField<T extends FieldValues, Nullable extends boolean, TransformedValue = [never]>(
	inProps: RHFTextFieldProps<T, Nullable, TransformedValue>
) {
	const {
		/** React Hook Form */
		name,
		rules,
		control,
		disabled,
		defaultValue,
		shouldUnregister,
		/** React Hook Form */
		required,
		transform,
		helperText,
		label,
		onChange,
		onBlur,
		inputRef,
		...props
	} = useDefaultProps({ name: 'RemateRHFTextField', props: inProps });

	const { translate } = useLocalization();

	const {
		field,
		fieldState: { error }
	} = useController<T>({
		name,
		control,
		defaultValue,
		shouldUnregister,
		disabled,
		rules: rules && {
			...rules,
			required: rules?.required === true ? translate('validation.required', { label }) : rules?.required,
			pattern: isRegExp(rules?.pattern)
				? {
						value: rules.pattern,
						message: translate('validation.pattern', { label, pattern: rules.pattern })
					}
				: rules?.pattern,
			minLength: isNumber(rules?.minLength)
				? {
						value: rules.minLength,
						message: translate('validation.minLength', { minLength: rules.minLength, label })
					}
				: rules?.minLength,
			maxLength: isNumber(rules?.maxLength)
				? {
						value: rules.maxLength,
						message: translate('validation.maxLength', { maxLength: rules.maxLength, label })
					}
				: rules?.maxLength
		}
	});

	const isFieldRequired = isBoolean(rules?.required)
		? rules.required
		: isString(rules?.required) || rules?.required?.value || required;

	const onChangeHandler = (value: any, event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
		if (isFunction(transform)) {
			value = transform(value);
		}

		field.onChange(value);
		onChange?.(value, event);
	};

	const onBlurHandler = (e: React.FocusEvent<HTMLInputElement>) => {
		field.onBlur();
		onBlur?.(e);
	};

	return (
		<TextField
			fullWidth
			{...props}
			label={label}
			inputRef={inputRef ?? field.ref}
			name={field.name}
			disabled={field.disabled}
			value={field.value}
			onChange={onChangeHandler}
			onBlur={onBlurHandler}
			required={isFieldRequired}
			error={!!error}
			helperText={error?.message ?? helperText}
		/>
	);
}

declare module '@mui/material' {
	interface Components {
		RemateRHFTextField?: {
			defaultProps?: Partial<RHFTextFieldProps>;
		};
	}
}

export default RHFTextField;
