import { FileRejection } from 'react-dropzone';
import { FieldValues, useController, UseControllerProps } from 'react-hook-form';
import { isBoolean, isFunction, isString } from 'lodash';

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

export type RHFUploadProps<T extends FieldValues = FieldValues, TMultiple extends boolean | undefined = false> = Omit<
	UploadProps<TMultiple>,
	'onDrop' | 'onDelete' | 'onRemove' | 'onRemoveAll' | 'onUpload' | 'value' | 'disabled' | 'error'
> &
	UseControllerProps<T> & {
		onChange?: (value: TMultiple extends true ? File[] : File) => void;
		onUpload?: (value: TMultiple extends true ? File[] : File) => void;
		transform?: (
			value: TMultiple extends true ? File[] : File
		) => TMultiple extends true ? File[] | Promise<File[]> : File | Promise<File>;
	};

function RHFUpload<T extends FieldValues, TMultiple extends boolean | undefined = false>(
	inProps: RHFUploadProps<T, TMultiple>
) {
	const {
		/** React Hook Form */
		name,
		rules,
		control,
		disabled,
		defaultValue,
		shouldUnregister,
		/** React Hook Form */

		multiple = false,
		helperText,
		label,
		onChange,
		required,
		transform,
		onUpload: onUploadFromProps,

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

	const { translate } = useLocalization();

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

	function changeHandler(value: any) {
		field.onChange(value);
		onChange?.(value);
	}

	async function onDrop(acceptedFiles: File[], rejectionFiles: FileRejection[]) {
		if (rejectionFiles.length) {
			return;
		}

		let value = multiple ? [...(field.value ?? []), ...acceptedFiles] : acceptedFiles[0];

		if (isFunction(transform)) {
			try {
				value = await transform(value as any);
			} catch {
				return;
			}
		}

		changeHandler(value);
	}

	return (
		<Upload
			{...other}
			name={field.name}
			onBlur={field.onBlur}
			ref={field.ref}
			multiple={multiple}
			label={label}
			required={
				isBoolean(rules?.required) ? rules.required : isString(rules?.required) || rules?.required?.value || required
			}
			error={!!error}
			helperText={error?.message ?? helperText}
			value={field.value}
			disabled={field.disabled}
			onDrop={onDrop}
			onDelete={() => changeHandler(null)}
			onRemove={(file) => {
				changeHandler(field.value.filter((v: File) => v !== file));
			}}
			onRemoveAll={() => changeHandler([])}
			{...(isFunction(onUploadFromProps) && {
				onUpload: () => {
					onUploadFromProps(field.value);
				}
			})}
		/>
	);
}

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

export default RHFUpload;
