import { __assign } from "tslib";
import { GetOption, setInternalSlot, SupportedLocales, getInternalSlot, PartitionPattern, invariant, isLiteralPart, GetOptionsObject, CanonicalizeLocaleList, } from '@formatjs/ecma402-abstract';
import { ResolveLocale } from '@formatjs/intl-localematcher';
function validateInstance(instance, method) {
    if (!(instance instanceof ListFormat)) {
        throw new TypeError("Method Intl.ListFormat.prototype.".concat(method, " called on incompatible receiver ").concat(String(instance)));
    }
}
/**
 * https://tc39.es/proposal-intl-list-format/#sec-createstringlistfromiterable
 * @param list list
 */
function stringListFromIterable(list) {
    if (list === undefined) {
        return [];
    }
    var result = [];
    for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
        var el = list_1[_i];
        if (typeof el !== 'string') {
            throw new TypeError("array list[".concat(list.indexOf(el), "] is not type String"));
        }
        result.push(el);
    }
    return result;
}
function createPartsFromList(internalSlotMap, lf, list) {
    var size = list.length;
    if (size === 0) {
        return [];
    }
    if (size === 2) {
        var pattern = getInternalSlot(internalSlotMap, lf, 'templatePair');
        var first = { type: 'element', value: list[0] };
        var second = { type: 'element', value: list[1] };
        return deconstructPattern(pattern, { '0': first, '1': second });
    }
    var last = {
        type: 'element',
        value: list[size - 1],
    };
    var parts = last;
    var i = size - 2;
    while (i >= 0) {
        var pattern = void 0;
        if (i === 0) {
            pattern = getInternalSlot(internalSlotMap, lf, 'templateStart');
        }
        else if (i < size - 2) {
            pattern = getInternalSlot(internalSlotMap, lf, 'templateMiddle');
        }
        else {
            pattern = getInternalSlot(internalSlotMap, lf, 'templateEnd');
        }
        var head = { type: 'element', value: list[i] };
        parts = deconstructPattern(pattern, { '0': head, '1': parts });
        i--;
    }
    return parts;
}
function deconstructPattern(pattern, placeables) {
    var patternParts = PartitionPattern(pattern);
    var result = [];
    for (var _i = 0, patternParts_1 = patternParts; _i < patternParts_1.length; _i++) {
        var patternPart = patternParts_1[_i];
        var part = patternPart.type;
        if (isLiteralPart(patternPart)) {
            result.push({
                type: 'literal',
                value: patternPart.value,
            });
        }
        else {
            invariant(part in placeables, "".concat(part, " is missing from placables"));
            var subst = placeables[part];
            if (Array.isArray(subst)) {
                result.push.apply(result, subst);
            }
            else {
                result.push(subst);
            }
        }
    }
    return result;
}
var ListFormat = /** @class */ (function () {
    function ListFormat(locales, options) {
        // test262/test/intl402/ListFormat/constructor/constructor/newtarget-undefined.js
        // Cannot use `new.target` bc of IE11 & TS transpiles it to something else
        var newTarget = this && this instanceof ListFormat ? this.constructor : void 0;
        if (!newTarget) {
            throw new TypeError("Intl.ListFormat must be called with 'new'");
        }
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'initializedListFormat', true);
        var requestedLocales = CanonicalizeLocaleList(locales);
        var opt = Object.create(null);
        var opts = GetOptionsObject(options);
        var matcher = GetOption(opts, 'localeMatcher', 'string', ['best fit', 'lookup'], 'best fit');
        opt.localeMatcher = matcher;
        var localeData = ListFormat.localeData;
        var r = ResolveLocale(ListFormat.availableLocales, requestedLocales, opt, ListFormat.relevantExtensionKeys, localeData, ListFormat.getDefaultLocale);
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'locale', r.locale);
        var type = GetOption(opts, 'type', 'string', ['conjunction', 'disjunction', 'unit'], 'conjunction');
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'type', type);
        var style = GetOption(opts, 'style', 'string', ['long', 'short', 'narrow'], 'long');
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'style', style);
        var dataLocale = r.dataLocale;
        var dataLocaleData = localeData[dataLocale];
        invariant(!!dataLocaleData, "Missing locale data for ".concat(dataLocale));
        var dataLocaleTypes = dataLocaleData[type];
        var templates = dataLocaleTypes[style];
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'templatePair', templates.pair);
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'templateStart', templates.start);
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'templateMiddle', templates.middle);
        setInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'templateEnd', templates.end);
    }
    ListFormat.prototype.format = function (elements) {
        validateInstance(this, 'format');
        var result = '';
        var parts = createPartsFromList(ListFormat.__INTERNAL_SLOT_MAP__, this, stringListFromIterable(elements));
        if (!Array.isArray(parts)) {
            return parts.value;
        }
        for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
            var p = parts_1[_i];
            result += p.value;
        }
        return result;
    };
    ListFormat.prototype.formatToParts = function (elements) {
        validateInstance(this, 'format');
        var parts = createPartsFromList(ListFormat.__INTERNAL_SLOT_MAP__, this, stringListFromIterable(elements));
        if (!Array.isArray(parts)) {
            return [parts];
        }
        var result = [];
        for (var _i = 0, parts_2 = parts; _i < parts_2.length; _i++) {
            var part = parts_2[_i];
            result.push(__assign({}, part));
        }
        return result;
    };
    ListFormat.prototype.resolvedOptions = function () {
        validateInstance(this, 'resolvedOptions');
        return {
            locale: getInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'locale'),
            type: getInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'type'),
            style: getInternalSlot(ListFormat.__INTERNAL_SLOT_MAP__, this, 'style'),
        };
    };
    ListFormat.supportedLocalesOf = function (locales, options) {
        // test262/test/intl402/ListFormat/constructor/supportedLocalesOf/result-type.js
        return SupportedLocales(ListFormat.availableLocales, CanonicalizeLocaleList(locales), options);
    };
    ListFormat.__addLocaleData = function () {
        var data = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            data[_i] = arguments[_i];
        }
        for (var _a = 0, data_1 = data; _a < data_1.length; _a++) {
            var _b = data_1[_a], d = _b.data, locale = _b.locale;
            var minimizedLocale = new Intl.Locale(locale)
                .minimize()
                .toString();
            ListFormat.localeData[locale] = ListFormat.localeData[minimizedLocale] = d;
            ListFormat.availableLocales.add(minimizedLocale);
            ListFormat.availableLocales.add(locale);
            if (!ListFormat.__defaultLocale) {
                ListFormat.__defaultLocale = minimizedLocale;
            }
        }
    };
    ListFormat.getDefaultLocale = function () {
        return ListFormat.__defaultLocale;
    };
    ListFormat.localeData = {};
    ListFormat.availableLocales = new Set();
    ListFormat.__defaultLocale = '';
    ListFormat.relevantExtensionKeys = [];
    ListFormat.polyfilled = true;
    ListFormat.__INTERNAL_SLOT_MAP__ = new WeakMap();
    return ListFormat;
}());
export default ListFormat;
try {
    // IE11 does not have Symbol
    if (typeof Symbol !== 'undefined') {
        Object.defineProperty(ListFormat.prototype, Symbol.toStringTag, {
            value: 'Intl.ListFormat',
            writable: false,
            enumerable: false,
            configurable: true,
        });
    }
    // https://github.com/tc39/test262/blob/master/test/intl402/ListFormat/constructor/length.js
    Object.defineProperty(ListFormat.prototype.constructor, 'length', {
        value: 0,
        writable: false,
        enumerable: false,
        configurable: true,
    });
    // https://github.com/tc39/test262/blob/master/test/intl402/ListFormat/constructor/supportedLocalesOf/length.js
    Object.defineProperty(ListFormat.supportedLocalesOf, 'length', {
        value: 1,
        writable: false,
        enumerable: false,
        configurable: true,
    });
}
catch (e) {
    // Meta fix so we're test262-compliant, not important
}
