import { addMinutes, format, formatDistanceToNowStrict, isValid, parse } from "date-fns";
import { enUS } from "date-fns/locale";

const formatString = "dd/MM/yyyy";

const dateToString = (date: Date, formatDate = formatString): string => format(new Date(date), formatDate);

const stringToDate = (value: string): Date => {
	const regEx = /^[0-9]{4}[\/][0-9]{2}[\/][0-9]{2}$/g;
	const isInversed = regEx.test(value);
	const formatDate = isInversed ? "yyyy/MM/dd" : "dd/MM/yyyy";

	return parse(value, formatDate, new Date());
};

const isValidDate = (value: string): boolean => {
	const regEx = /^[0-9]{4}[\/][0-9]{2}[\/][0-9]{2}$/g;
	const regEx2 = /^[0-9]{2}[\/][0-9]{2}[\/][0-9]{4}$/g;

	if (regEx.test(value) || regEx2.test(value)) {
		const date = stringToDate(value);
		return isValid(date);
	}
	return false;
};

const getRange = (value: string) => value.split(" ").join("").trim().split("-");

const isValidDateRange = (value: string): boolean => {
	const range = getRange(value);
	return isValidDate(range[0]) && isValidDate(range[1]);
};

const getDateRange = (value: string): { start: Date; end: Date | null } => {
	const range = getRange(value);

	const startDate = range[0];
	const endDate = range[1];

	const rangeStartDate = stringToDate(startDate);
	const rangeEndDate = endDate && stringToDate(endDate);

	return {
		start: rangeStartDate,
		end: rangeEndDate ? rangeEndDate : rangeStartDate,
	};
};

const areEqualDates = (date1: Date, date2: Date): boolean => dateToString(date1) === dateToString(date2);

const getStringifyDateRange = (start: Date, end: Date, formatDate?: string): string => {
	const equalRangeDates = areEqualDates(start, end);

	const stringifyDates = {
		start: start ? dateToString(start, formatDate) : "",
		end: end ? dateToString(end, formatDate) : "",
	};

	return end && !equalRangeDates ? `${stringifyDates.start} - ${stringifyDates.end}` : stringifyDates.start;
};

const getHumanLastModifiedDate = (modified: Date): string => {
	const now = new Date();
	const date = new Date(modified);

	const oneDay = 60 * 60 * 24 * 1000;
	const isMoreThan24Hours = now.getTime() - date.getTime() > oneDay;

	return isMoreThan24Hours ? format(date, "d MMM HH:mm") : formatDistanceToNowStrict(date, { addSuffix: true });
};

const getFormattedDateWithTimezone = (date: Date, formatString: string): string => {
	const objDate = new Date(date);
	return format(addMinutes(objDate, objDate.getTimezoneOffset()), formatString);
};

const getDaysAgo = (date: Date): string => {
	const dateObj = new Date(date);
	return formatDistanceToNowStrict(dateObj, { addSuffix: true });
};

const getScheduleFormatDate = (date: string): string => {
	const dateObj = parse(date, "dd/MM/yyyy HH:mm:ss", new Date());
	return dateToString(dateObj, "dd/MM/yy · HH:mm");
};

const formatDate = (date: number | Date): string => {
	return format(date, "MMMM d, yyyy", { locale: enUS });
};

export {
	areEqualDates,
	dateToString,
	formatDate,
	getDateRange,
	getDaysAgo,
	getFormattedDateWithTimezone,
	getHumanLastModifiedDate,
	getRange,
	getScheduleFormatDate,
	getStringifyDateRange,
	isValidDate,
	isValidDateRange,
	stringToDate,
};
