const require_IANAZone = require('../zones/IANAZone.js');
const require_settings = require('../settings.js');
const require_util = require('./util.js');
const require_english = require('./english.js');
const require_datetime = require('../datetime.js');

//#region ../../node_modules/.pnpm/luxon@3.5.0/node_modules/luxon/src/impl/locale.js
let intlLFCache = {};
function getCachedLF(locString, opts = {}) {
	const key = JSON.stringify([locString, opts]);
	let dtf = intlLFCache[key];
	if (!dtf) {
		dtf = new Intl.ListFormat(locString, opts);
		intlLFCache[key] = dtf;
	}
	return dtf;
}
let intlDTCache = {};
function getCachedDTF(locString, opts = {}) {
	const key = JSON.stringify([locString, opts]);
	let dtf = intlDTCache[key];
	if (!dtf) {
		dtf = new Intl.DateTimeFormat(locString, opts);
		intlDTCache[key] = dtf;
	}
	return dtf;
}
let intlNumCache = {};
function getCachedINF(locString, opts = {}) {
	const key = JSON.stringify([locString, opts]);
	let inf = intlNumCache[key];
	if (!inf) {
		inf = new Intl.NumberFormat(locString, opts);
		intlNumCache[key] = inf;
	}
	return inf;
}
let intlRelCache = {};
function getCachedRTF(locString, opts = {}) {
	const { base,...cacheKeyOpts } = opts;
	const key = JSON.stringify([locString, cacheKeyOpts]);
	let inf = intlRelCache[key];
	if (!inf) {
		inf = new Intl.RelativeTimeFormat(locString, opts);
		intlRelCache[key] = inf;
	}
	return inf;
}
let sysLocaleCache = null;
function systemLocale() {
	if (sysLocaleCache) return sysLocaleCache;
	else {
		sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
		return sysLocaleCache;
	}
}
let weekInfoCache = {};
function getCachedWeekInfo(locString) {
	let data = weekInfoCache[locString];
	if (!data) {
		const locale = new Intl.Locale(locString);
		data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
		weekInfoCache[locString] = data;
	}
	return data;
}
function parseLocaleString(localeStr) {
	const xIndex = localeStr.indexOf("-x-");
	if (xIndex !== -1) localeStr = localeStr.substring(0, xIndex);
	const uIndex = localeStr.indexOf("-u-");
	if (uIndex === -1) return [localeStr];
	else {
		let options;
		let selectedStr;
		try {
			options = getCachedDTF(localeStr).resolvedOptions();
			selectedStr = localeStr;
		} catch (e) {
			const smaller = localeStr.substring(0, uIndex);
			options = getCachedDTF(smaller).resolvedOptions();
			selectedStr = smaller;
		}
		const { numberingSystem, calendar } = options;
		return [
			selectedStr,
			numberingSystem,
			calendar
		];
	}
}
function intlConfigString(localeStr, numberingSystem, outputCalendar) {
	if (outputCalendar || numberingSystem) {
		if (!localeStr.includes("-u-")) localeStr += "-u";
		if (outputCalendar) localeStr += `-ca-${outputCalendar}`;
		if (numberingSystem) localeStr += `-nu-${numberingSystem}`;
		return localeStr;
	} else return localeStr;
}
function mapMonths(f) {
	const ms = [];
	for (let i = 1; i <= 12; i++) {
		const dt = require_datetime.default.utc(2009, i, 1);
		ms.push(f(dt));
	}
	return ms;
}
function mapWeekdays(f) {
	const ms = [];
	for (let i = 1; i <= 7; i++) {
		const dt = require_datetime.default.utc(2016, 11, 13 + i);
		ms.push(f(dt));
	}
	return ms;
}
function listStuff(loc, length, englishFn, intlFn) {
	const mode = loc.listingMode();
	if (mode === "error") return null;
	else if (mode === "en") return englishFn(length);
	else return intlFn(length);
}
function supportsFastNumbers(loc) {
	if (loc.numberingSystem && loc.numberingSystem !== "latn") return false;
	else return loc.numberingSystem === "latn" || !loc.locale || loc.locale.startsWith("en") || new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn";
}
/**
* @private
*/
var PolyNumberFormatter = class {
	constructor(intl, forceSimple, opts) {
		this.padTo = opts.padTo || 0;
		this.floor = opts.floor || false;
		const { padTo, floor,...otherOpts } = opts;
		if (!forceSimple || Object.keys(otherOpts).length > 0) {
			const intlOpts = {
				useGrouping: false,
				...opts
			};
			if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
			this.inf = getCachedINF(intl, intlOpts);
		}
	}
	format(i) {
		if (this.inf) {
			const fixed = this.floor ? Math.floor(i) : i;
			return this.inf.format(fixed);
		} else return require_util.padStart(this.floor ? Math.floor(i) : require_util.roundTo(i, 3), this.padTo);
	}
};
/**
* @private
*/
var PolyDateFormatter = class {
	constructor(dt, intl, opts) {
		this.opts = opts;
		this.originalZone = void 0;
		let z = void 0;
		if (this.opts.timeZone) this.dt = dt;
		else if (dt.zone.type === "fixed") {
			const gmtOffset = -1 * (dt.offset / 60);
			const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
			if (dt.offset !== 0 && require_IANAZone.default.create(offsetZ).valid) {
				z = offsetZ;
				this.dt = dt;
			} else {
				z = "UTC";
				this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
				this.originalZone = dt.zone;
			}
		} else if (dt.zone.type === "system") this.dt = dt;
		else if (dt.zone.type === "iana") {
			this.dt = dt;
			z = dt.zone.name;
		} else {
			z = "UTC";
			this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
			this.originalZone = dt.zone;
		}
		const intlOpts = { ...this.opts };
		intlOpts.timeZone = intlOpts.timeZone || z;
		this.dtf = getCachedDTF(intl, intlOpts);
	}
	format() {
		if (this.originalZone) return this.formatToParts().map(({ value }) => value).join("");
		return this.dtf.format(this.dt.toJSDate());
	}
	formatToParts() {
		const parts = this.dtf.formatToParts(this.dt.toJSDate());
		if (this.originalZone) return parts.map((part) => {
			if (part.type === "timeZoneName") {
				const offsetName = this.originalZone.offsetName(this.dt.ts, {
					locale: this.dt.locale,
					format: this.opts.timeZoneName
				});
				return {
					...part,
					value: offsetName
				};
			} else return part;
		});
		return parts;
	}
	resolvedOptions() {
		return this.dtf.resolvedOptions();
	}
};
/**
* @private
*/
var PolyRelFormatter = class {
	constructor(intl, isEnglish, opts) {
		this.opts = {
			style: "long",
			...opts
		};
		if (!isEnglish && require_util.hasRelative()) this.rtf = getCachedRTF(intl, opts);
	}
	format(count, unit) {
		if (this.rtf) return this.rtf.format(count, unit);
		else return require_english.formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
	}
	formatToParts(count, unit) {
		if (this.rtf) return this.rtf.formatToParts(count, unit);
		else return [];
	}
};
const fallbackWeekSettings = {
	firstDay: 1,
	minimalDays: 4,
	weekend: [6, 7]
};
/**
* @private
*/
var Locale = class Locale {
	static fromOpts(opts) {
		return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.weekSettings, opts.defaultToEN);
	}
	static create(locale, numberingSystem, outputCalendar, weekSettings, defaultToEN = false) {
		const specifiedLocale = locale || require_settings.default.defaultLocale;
		return new Locale(specifiedLocale || (defaultToEN ? "en-US" : systemLocale()), numberingSystem || require_settings.default.defaultNumberingSystem, outputCalendar || require_settings.default.defaultOutputCalendar, require_util.validateWeekSettings(weekSettings) || require_settings.default.defaultWeekSettings, specifiedLocale);
	}
	static resetCache() {
		sysLocaleCache = null;
		intlDTCache = {};
		intlNumCache = {};
		intlRelCache = {};
	}
	static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
		return Locale.create(locale, numberingSystem, outputCalendar, weekSettings);
	}
	constructor(locale, numbering, outputCalendar, weekSettings, specifiedLocale) {
		const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
		this.locale = parsedLocale;
		this.numberingSystem = numbering || parsedNumberingSystem || null;
		this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
		this.weekSettings = weekSettings;
		this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
		this.weekdaysCache = {
			format: {},
			standalone: {}
		};
		this.monthsCache = {
			format: {},
			standalone: {}
		};
		this.meridiemCache = null;
		this.eraCache = {};
		this.specifiedLocale = specifiedLocale;
		this.fastNumbersCached = null;
	}
	get fastNumbers() {
		if (this.fastNumbersCached == null) this.fastNumbersCached = supportsFastNumbers(this);
		return this.fastNumbersCached;
	}
	listingMode() {
		const isActuallyEn = this.isEnglish();
		const hasNoWeirdness = (this.numberingSystem === null || this.numberingSystem === "latn") && (this.outputCalendar === null || this.outputCalendar === "gregory");
		return isActuallyEn && hasNoWeirdness ? "en" : "intl";
	}
	clone(alts) {
		if (!alts || Object.getOwnPropertyNames(alts).length === 0) return this;
		else return Locale.create(alts.locale || this.specifiedLocale, alts.numberingSystem || this.numberingSystem, alts.outputCalendar || this.outputCalendar, require_util.validateWeekSettings(alts.weekSettings) || this.weekSettings, alts.defaultToEN || false);
	}
	redefaultToEN(alts = {}) {
		return this.clone({
			...alts,
			defaultToEN: true
		});
	}
	redefaultToSystem(alts = {}) {
		return this.clone({
			...alts,
			defaultToEN: false
		});
	}
	months(length, format = false) {
		return listStuff(this, length, require_english.months, () => {
			const intl = format ? {
				month: length,
				day: "numeric"
			} : { month: length }, formatStr = format ? "format" : "standalone";
			if (!this.monthsCache[formatStr][length]) this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
			return this.monthsCache[formatStr][length];
		});
	}
	weekdays(length, format = false) {
		return listStuff(this, length, require_english.weekdays, () => {
			const intl = format ? {
				weekday: length,
				year: "numeric",
				month: "long",
				day: "numeric"
			} : { weekday: length }, formatStr = format ? "format" : "standalone";
			if (!this.weekdaysCache[formatStr][length]) this.weekdaysCache[formatStr][length] = mapWeekdays((dt) => this.extract(dt, intl, "weekday"));
			return this.weekdaysCache[formatStr][length];
		});
	}
	meridiems() {
		return listStuff(this, void 0, () => require_english.meridiems, () => {
			if (!this.meridiemCache) {
				const intl = {
					hour: "numeric",
					hourCycle: "h12"
				};
				this.meridiemCache = [require_datetime.default.utc(2016, 11, 13, 9), require_datetime.default.utc(2016, 11, 13, 19)].map((dt) => this.extract(dt, intl, "dayperiod"));
			}
			return this.meridiemCache;
		});
	}
	eras(length) {
		return listStuff(this, length, require_english.eras, () => {
			const intl = { era: length };
			if (!this.eraCache[length]) this.eraCache[length] = [require_datetime.default.utc(-40, 1, 1), require_datetime.default.utc(2017, 1, 1)].map((dt) => this.extract(dt, intl, "era"));
			return this.eraCache[length];
		});
	}
	extract(dt, intlOpts, field) {
		const matching = this.dtFormatter(dt, intlOpts).formatToParts().find((m) => m.type.toLowerCase() === field);
		return matching ? matching.value : null;
	}
	numberFormatter(opts = {}) {
		return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
	}
	dtFormatter(dt, intlOpts = {}) {
		return new PolyDateFormatter(dt, this.intl, intlOpts);
	}
	relFormatter(opts = {}) {
		return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
	}
	listFormatter(opts = {}) {
		return getCachedLF(this.intl, opts);
	}
	isEnglish() {
		return this.locale === "en" || this.locale.toLowerCase() === "en-us" || new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");
	}
	getWeekSettings() {
		if (this.weekSettings) return this.weekSettings;
		else if (!require_util.hasLocaleWeekInfo()) return fallbackWeekSettings;
		else return getCachedWeekInfo(this.locale);
	}
	getStartOfWeek() {
		return this.getWeekSettings().firstDay;
	}
	getMinDaysInFirstWeek() {
		return this.getWeekSettings().minimalDays;
	}
	getWeekendDays() {
		return this.getWeekSettings().weekend;
	}
	equals(other) {
		return this.locale === other.locale && this.numberingSystem === other.numberingSystem && this.outputCalendar === other.outputCalendar;
	}
	toString() {
		return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`;
	}
};

//#endregion
exports.default = Locale;