const require_errors = require('../errors.js');
const require_invalid = require('./invalid.js');
const require_util = require('./util.js');

//#region ../../node_modules/.pnpm/luxon@3.5.0/node_modules/luxon/src/impl/conversions.js
const nonLeapLadder = [
	0,
	31,
	59,
	90,
	120,
	151,
	181,
	212,
	243,
	273,
	304,
	334
], leapLadder = [
	0,
	31,
	60,
	91,
	121,
	152,
	182,
	213,
	244,
	274,
	305,
	335
];
function unitOutOfRange(unit, value) {
	return new require_invalid.default("unit out of range", `you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid`);
}
function dayOfWeek(year, month, day) {
	const d = new Date(Date.UTC(year, month - 1, day));
	if (year < 100 && year >= 0) d.setUTCFullYear(d.getUTCFullYear() - 1900);
	const js = d.getUTCDay();
	return js === 0 ? 7 : js;
}
function computeOrdinal(year, month, day) {
	return day + (require_util.isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1];
}
function uncomputeOrdinal(year, ordinal) {
	const table = require_util.isLeapYear(year) ? leapLadder : nonLeapLadder, month0 = table.findIndex((i) => i < ordinal), day = ordinal - table[month0];
	return {
		month: month0 + 1,
		day
	};
}
function isoWeekdayToLocal(isoWeekday, startOfWeek) {
	return (isoWeekday - startOfWeek + 7) % 7 + 1;
}
/**
* @private
*/
function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = 1) {
	const { year, month, day } = gregObj, ordinal = computeOrdinal(year, month, day), weekday = isoWeekdayToLocal(dayOfWeek(year, month, day), startOfWeek);
	let weekNumber = Math.floor((ordinal - weekday + 14 - minDaysInFirstWeek) / 7), weekYear;
	if (weekNumber < 1) {
		weekYear = year - 1;
		weekNumber = require_util.weeksInWeekYear(weekYear, minDaysInFirstWeek, startOfWeek);
	} else if (weekNumber > require_util.weeksInWeekYear(year, minDaysInFirstWeek, startOfWeek)) {
		weekYear = year + 1;
		weekNumber = 1;
	} else weekYear = year;
	return {
		weekYear,
		weekNumber,
		weekday,
		...require_util.timeObject(gregObj)
	};
}
function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek = 1) {
	const { weekYear, weekNumber, weekday } = weekData, weekdayOfJan4 = isoWeekdayToLocal(dayOfWeek(weekYear, 1, minDaysInFirstWeek), startOfWeek), yearInDays = require_util.daysInYear(weekYear);
	let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 7 + minDaysInFirstWeek, year;
	if (ordinal < 1) {
		year = weekYear - 1;
		ordinal += require_util.daysInYear(year);
	} else if (ordinal > yearInDays) {
		year = weekYear + 1;
		ordinal -= require_util.daysInYear(weekYear);
	} else year = weekYear;
	const { month, day } = uncomputeOrdinal(year, ordinal);
	return {
		year,
		month,
		day,
		...require_util.timeObject(weekData)
	};
}
function gregorianToOrdinal(gregData) {
	const { year, month, day } = gregData;
	return {
		year,
		ordinal: computeOrdinal(year, month, day),
		...require_util.timeObject(gregData)
	};
}
function ordinalToGregorian(ordinalData) {
	const { year, ordinal } = ordinalData;
	const { month, day } = uncomputeOrdinal(year, ordinal);
	return {
		year,
		month,
		day,
		...require_util.timeObject(ordinalData)
	};
}
/**
* Check if local week units like localWeekday are used in obj.
* If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties.
* Modifies obj in-place!
* @param obj the object values
*/
function usesLocalWeekValues(obj, loc) {
	if (!require_util.isUndefined(obj.localWeekday) || !require_util.isUndefined(obj.localWeekNumber) || !require_util.isUndefined(obj.localWeekYear)) {
		if (!require_util.isUndefined(obj.weekday) || !require_util.isUndefined(obj.weekNumber) || !require_util.isUndefined(obj.weekYear)) throw new require_errors.ConflictingSpecificationError("Cannot mix locale-based week fields with ISO-based week fields");
		if (!require_util.isUndefined(obj.localWeekday)) obj.weekday = obj.localWeekday;
		if (!require_util.isUndefined(obj.localWeekNumber)) obj.weekNumber = obj.localWeekNumber;
		if (!require_util.isUndefined(obj.localWeekYear)) obj.weekYear = obj.localWeekYear;
		delete obj.localWeekday;
		delete obj.localWeekNumber;
		delete obj.localWeekYear;
		return {
			minDaysInFirstWeek: loc.getMinDaysInFirstWeek(),
			startOfWeek: loc.getStartOfWeek()
		};
	} else return {
		minDaysInFirstWeek: 4,
		startOfWeek: 1
	};
}
function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) {
	const validYear = require_util.isInteger(obj.weekYear), validWeek = require_util.integerBetween(obj.weekNumber, 1, require_util.weeksInWeekYear(obj.weekYear, minDaysInFirstWeek, startOfWeek)), validWeekday = require_util.integerBetween(obj.weekday, 1, 7);
	if (!validYear) return unitOutOfRange("weekYear", obj.weekYear);
	else if (!validWeek) return unitOutOfRange("week", obj.weekNumber);
	else if (!validWeekday) return unitOutOfRange("weekday", obj.weekday);
	else return false;
}
function hasInvalidOrdinalData(obj) {
	const validYear = require_util.isInteger(obj.year), validOrdinal = require_util.integerBetween(obj.ordinal, 1, require_util.daysInYear(obj.year));
	if (!validYear) return unitOutOfRange("year", obj.year);
	else if (!validOrdinal) return unitOutOfRange("ordinal", obj.ordinal);
	else return false;
}
function hasInvalidGregorianData(obj) {
	const validYear = require_util.isInteger(obj.year), validMonth = require_util.integerBetween(obj.month, 1, 12), validDay = require_util.integerBetween(obj.day, 1, require_util.daysInMonth(obj.year, obj.month));
	if (!validYear) return unitOutOfRange("year", obj.year);
	else if (!validMonth) return unitOutOfRange("month", obj.month);
	else if (!validDay) return unitOutOfRange("day", obj.day);
	else return false;
}
function hasInvalidTimeData(obj) {
	const { hour, minute, second, millisecond } = obj;
	const validHour = require_util.integerBetween(hour, 0, 23) || hour === 24 && minute === 0 && second === 0 && millisecond === 0, validMinute = require_util.integerBetween(minute, 0, 59), validSecond = require_util.integerBetween(second, 0, 59), validMillisecond = require_util.integerBetween(millisecond, 0, 999);
	if (!validHour) return unitOutOfRange("hour", hour);
	else if (!validMinute) return unitOutOfRange("minute", minute);
	else if (!validSecond) return unitOutOfRange("second", second);
	else if (!validMillisecond) return unitOutOfRange("millisecond", millisecond);
	else return false;
}

//#endregion
exports.dayOfWeek = dayOfWeek;
exports.gregorianToOrdinal = gregorianToOrdinal;
exports.gregorianToWeek = gregorianToWeek;
exports.hasInvalidGregorianData = hasInvalidGregorianData;
exports.hasInvalidOrdinalData = hasInvalidOrdinalData;
exports.hasInvalidTimeData = hasInvalidTimeData;
exports.hasInvalidWeekData = hasInvalidWeekData;
exports.isoWeekdayToLocal = isoWeekdayToLocal;
exports.ordinalToGregorian = ordinalToGregorian;
exports.usesLocalWeekValues = usesLocalWeekValues;
exports.weekToGregorian = weekToGregorian;