/* eslint-disable @typescript-eslint/no-explicit-any */
import { setLocale, LocaleObject, TestMessageParams } from 'yup';
import type {IntlShape} from '../../components/intl';


/**
 * Wraps a validation failure from yup
 * @date 2020-10-24
 * @export
 * @class YupFail
 * @example
 * const schema = yup.schema({
 *  // we use createMessage to make sure we provide the correct function to min
 * 	name: yup.string.min(20, createMessage(
 * 		//we're taking the path and min properties of the min function's result
 * 		({path, label, min}) => {
 *			if (label) {
 *	 			// in yup messages, path represents the name of the field.
 * 				// if label is provided, that's a better name
 *				path = label;
 *			}
 * 			return new YupFail('translation.id.path',
 *          {path, min} // you HAVE to pass path here, even if the message doesn't use it
 * 			);
 * 		}
 * 	))
 * })
 *
 * // the yup schema was passed into Formik and formikConfig.errors has been set for the name
 * // field. We assume the `errors` const has latest formikConfig.errors
 *
 * // the below code is part of a TSX component
 * <ul className="errorListForName">
 * 	{
 * 		errors.name.map((yupFail:YupFail) => (
 * 				<li key={yupFail.id} className="errorItem">{formatMessage(...yupFail.message)</li>
 * 			)
 * 		)
 * 	}
 * </ul>
 *
 */
export class YupFail {

	/**
	 * Creates an instance of Description.
	 * @date 2020-10-24
	 * @param id the translation ID of the failure message
	 * @param values the values to be interpolated into the failure message ID'd by {@link id}
	 */
	constructor(readonly id: string, readonly values: Parameters<ToPropResult>[0]) {
		this.id = id;
		this.values = values;
		Object.bind(this, this.message);
	}

	get message(): Parameters<IntlShape['formatMessage']> {
		return [{id:this.id}, this.values];
	}

}
type RequiredValueProps = {path:string};
/**
 * A spec
 */
type TestOptionsMessageFn<Extra extends Record<string, any> = Record<string, any>, R = any> =
	| ((params: Extra & Partial<TestMessageParams> & RequiredValueProps) => R)



export type ToPropResult<Extra extends Record<string, any> = Record<string, any>> = TestOptionsMessageFn<Extra, YupFail>


/**
 * A function used for improving typescript safety when manually creating your
 * own validation messages
 * @param fn a function
 */
export function createMessage<Extra extends Record<string, any> = Record<string, any>>(fn: ToPropResult<Extra>): ToPropResult<Extra> {
	return fn;
}



// }

type HoudiniYupLocaleObject = Required<LocaleObject>;

// TODO: we could optimize this and only run it the first time the module is
// loaded

const locale: HoudiniYupLocaleObject = {
	mixed: {
		default: message("yup.mixed.default"),
		required: message("yup.mixed.required"),
		oneOf: message("yup.mixed.oneOf"),
		notOneOf: message("yup.mixed.notOneOf"),
	},
	string: {
		length: message("yup.string.length"),
		min: message("yup.string.min"),
		max: message("yup.string.max"),
		matches: message("yup.string.regex"),
		email: message("yup.string.email"),
		url: message("yup.string.url"),
		uuid: message("yup.string.uuid"),
		trim: message("yup.string.trim"),
		lowercase: message("yup.string.lowercase"),
		uppercase: message("yup.string.uppercase"),
	},
	number: {
		min: message("yup.number.min"),
		max: message("yup.string.max"),
		lessThan: message("yup.number.lessThan"),
		moreThan: message("yup.number.moreThan"),

		positive: message("yup.number.postive"),
		negative: message("yup.number.negative"),
		integer: message("yup.number.integer"),
	},
	date: {
		min: message("yup.date.min"),
		max: message("yup.data.max"),
	},

	boolean: {

	},
	object: {
		noUnknown: message("yup.object.noUnknown"),
	},

	array: {
		min: message("yup.array.min"),
		max: message("yup.array.max"),
	},
};

function message<Extra extends Record<string, any> = Record<string, unknown>>(id: string): ToPropResult<Extra> {
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	return createMessage(({ path, label, value, originalValue, ...other }) => {
		if (label) {
			path = label;
		}
		return new YupFail(id, { path, ...other });
	});
}
setLocale(locale);