const require_errors = require('../errors.js');
const require_settings = require('../settings.js');
const require_conversions = require('./conversions.js');

//#region ../../node_modules/.pnpm/luxon@3.5.0/node_modules/luxon/src/impl/util.js
/**
* @private
*/
function isUndefined(o) {
	return typeof o === "undefined";
}
function isNumber(o) {
	return typeof o === "number";
}
function isInteger(o) {
	return typeof o === "number" && o % 1 === 0;
}
function isString(o) {
	return typeof o === "string";
}
function isDate(o) {
	return Object.prototype.toString.call(o) === "[object Date]";
}
function hasRelative() {
	try {
		return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
	} catch (e) {
		return false;
	}
}
function hasLocaleWeekInfo() {
	try {
		return typeof Intl !== "undefined" && !!Intl.Locale && ("weekInfo" in Intl.Locale.prototype || "getWeekInfo" in Intl.Locale.prototype);
	} catch (e) {
		return false;
	}
}
function maybeArray(thing) {
	return Array.isArray(thing) ? thing : [thing];
}
function bestBy(arr, by, compare) {
	if (arr.length === 0) return;
	return arr.reduce((best, next) => {
		const pair = [by(next), next];
		if (!best) return pair;
		else if (compare(best[0], pair[0]) === best[0]) return best;
		else return pair;
	}, null)[1];
}
function pick(obj, keys) {
	return keys.reduce((a, k) => {
		a[k] = obj[k];
		return a;
	}, {});
}
function hasOwnProperty(obj, prop) {
	return Object.prototype.hasOwnProperty.call(obj, prop);
}
function validateWeekSettings(settings) {
	if (settings == null) return null;
	else if (typeof settings !== "object") throw new require_errors.InvalidArgumentError("Week settings must be an object");
	else {
		if (!integerBetween(settings.firstDay, 1, 7) || !integerBetween(settings.minimalDays, 1, 7) || !Array.isArray(settings.weekend) || settings.weekend.some((v) => !integerBetween(v, 1, 7))) throw new require_errors.InvalidArgumentError("Invalid week settings");
		return {
			firstDay: settings.firstDay,
			minimalDays: settings.minimalDays,
			weekend: Array.from(settings.weekend)
		};
	}
}
function integerBetween(thing, bottom, top) {
	return isInteger(thing) && thing >= bottom && thing <= top;
}
function floorMod(x, n) {
	return x - n * Math.floor(x / n);
}
function padStart(input, n = 2) {
	const isNeg = input < 0;
	let padded;
	if (isNeg) padded = "-" + ("" + -input).padStart(n, "0");
	else padded = ("" + input).padStart(n, "0");
	return padded;
}
function parseInteger(string) {
	if (isUndefined(string) || string === null || string === "") return;
	else return parseInt(string, 10);
}
function parseFloating(string) {
	if (isUndefined(string) || string === null || string === "") return;
	else return parseFloat(string);
}
function parseMillis(fraction) {
	if (isUndefined(fraction) || fraction === null || fraction === "") return;
	else {
		const f = parseFloat("0." + fraction) * 1e3;
		return Math.floor(f);
	}
}
function roundTo(number, digits, towardZero = false) {
	const factor = 10 ** digits;
	return (towardZero ? Math.trunc : Math.round)(number * factor) / factor;
}
function isLeapYear(year) {
	return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
function daysInYear(year) {
	return isLeapYear(year) ? 366 : 365;
}
function daysInMonth(year, month) {
	const modMonth = floorMod(month - 1, 12) + 1, modYear = year + (month - modMonth) / 12;
	if (modMonth === 2) return isLeapYear(modYear) ? 29 : 28;
	else return [
		31,
		null,
		31,
		30,
		31,
		30,
		31,
		31,
		30,
		31,
		30,
		31
	][modMonth - 1];
}
function objToLocalTS(obj) {
	let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond);
	if (obj.year < 100 && obj.year >= 0) {
		d = new Date(d);
		d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
	}
	return +d;
}
function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) {
	return -require_conversions.isoWeekdayToLocal(require_conversions.dayOfWeek(year, 1, minDaysInFirstWeek), startOfWeek) + minDaysInFirstWeek - 1;
}
function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek = 1) {
	const weekOffset = firstWeekOffset(weekYear, minDaysInFirstWeek, startOfWeek);
	const weekOffsetNext = firstWeekOffset(weekYear + 1, minDaysInFirstWeek, startOfWeek);
	return (daysInYear(weekYear) - weekOffset + weekOffsetNext) / 7;
}
function untruncateYear(year) {
	if (year > 99) return year;
	else return year > require_settings.default.twoDigitCutoffYear ? 1900 + year : 2e3 + year;
}
function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
	const date = new Date(ts), intlOpts = {
		hourCycle: "h23",
		year: "numeric",
		month: "2-digit",
		day: "2-digit",
		hour: "2-digit",
		minute: "2-digit"
	};
	if (timeZone) intlOpts.timeZone = timeZone;
	const modified = {
		timeZoneName: offsetFormat,
		...intlOpts
	};
	const parsed = new Intl.DateTimeFormat(locale, modified).formatToParts(date).find((m) => m.type.toLowerCase() === "timezonename");
	return parsed ? parsed.value : null;
}
function signedOffset(offHourStr, offMinuteStr) {
	let offHour = parseInt(offHourStr, 10);
	if (Number.isNaN(offHour)) offHour = 0;
	const offMin = parseInt(offMinuteStr, 10) || 0, offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
	return offHour * 60 + offMinSigned;
}
function asNumber(value) {
	const numericValue = Number(value);
	if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) throw new require_errors.InvalidArgumentError(`Invalid unit value ${value}`);
	return numericValue;
}
function normalizeObject(obj, normalizer) {
	const normalized = {};
	for (const u in obj) if (hasOwnProperty(obj, u)) {
		const v = obj[u];
		if (v === void 0 || v === null) continue;
		normalized[normalizer(u)] = asNumber(v);
	}
	return normalized;
}
/**
* Returns the offset's value as a string
* @param {number} ts - Epoch milliseconds for which to get the offset
* @param {string} format - What style of offset to return.
*                          Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
* @return {string}
*/
function formatOffset(offset, format) {
	const hours = Math.trunc(Math.abs(offset / 60)), minutes = Math.trunc(Math.abs(offset % 60)), sign = offset >= 0 ? "+" : "-";
	switch (format) {
		case "short": return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
		case "narrow": return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
		case "techie": return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
		default: throw new RangeError(`Value format ${format} is out of range for property format`);
	}
}
function timeObject(obj) {
	return pick(obj, [
		"hour",
		"minute",
		"second",
		"millisecond"
	]);
}

//#endregion
exports.asNumber = asNumber;
exports.bestBy = bestBy;
exports.daysInMonth = daysInMonth;
exports.daysInYear = daysInYear;
exports.formatOffset = formatOffset;
exports.hasLocaleWeekInfo = hasLocaleWeekInfo;
exports.hasOwnProperty = hasOwnProperty;
exports.hasRelative = hasRelative;
exports.integerBetween = integerBetween;
exports.isDate = isDate;
exports.isInteger = isInteger;
exports.isLeapYear = isLeapYear;
exports.isNumber = isNumber;
exports.isString = isString;
exports.isUndefined = isUndefined;
exports.maybeArray = maybeArray;
exports.normalizeObject = normalizeObject;
exports.objToLocalTS = objToLocalTS;
exports.padStart = padStart;
exports.parseFloating = parseFloating;
exports.parseInteger = parseInteger;
exports.parseMillis = parseMillis;
exports.parseZoneInfo = parseZoneInfo;
exports.roundTo = roundTo;
exports.signedOffset = signedOffset;
exports.timeObject = timeObject;
exports.untruncateYear = untruncateYear;
exports.validateWeekSettings = validateWeekSettings;
exports.weeksInWeekYear = weeksInWeekYear;