import { isObject, hasOwnProperty, assign } from 'smob';

/*
 * Copyright (c) 2023.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ const LOCALE_DEFAULT = 'en';

function isLineRecord(value) {
    if (!isObject(value)) {
        return false;
    }
    const ob = value;
    const keys = Object.keys(ob);
    for(let i = 0; i < keys.length; i++){
        /* istanbul ignore next */ if (typeof ob[keys[i]] !== 'string' && !isLineRecord(ob[keys[i]])) {
            return false;
        }
    }
    return true;
}
function isLocaleContext(input) {
    return isObject(input) && hasOwnProperty(input, 'locale');
}
function isGroupContext(input) {
    return isObject(input) && hasOwnProperty(input, 'group');
}

/*
 * Copyright (c) 2023.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ function parseKey(key) {
    const index = key.indexOf('.');
    if (index === -1) {
        throw new SyntaxError('The key with required group prefix could not be parsed.');
    }
    const group = key.substring(0, index);
    const line = key.substring(group.length + 1);
    return [
        group,
        line
    ];
}

var aa = "Afar";
var ab = "Abkhazian";
var ae = "Avestan";
var af = "Afrikaans";
var ak = "Akan";
var am = "Amharic";
var an = "Aragonese";
var ar = "Arabic";
var as = "Assamese";
var av = "Avaric";
var ay = "Aymara";
var az = "Azerbaijani";
var ba = "Bashkir";
var be = "Belarusian";
var bg = "Bulgarian";
var bh = "Bihari languages";
var bi = "Bislama";
var bm = "Bambara";
var bn = "Bengali";
var bo = "Tibetan";
var br = "Breton";
var bs = "Bosnian";
var ca = "Catalan";
var ce = "Chechen";
var ch = "Chamorro";
var co = "Corsican";
var cr = "Cree";
var cs = "Czech";
var cu = "Church Slavic";
var cv = "Chuvash";
var cy = "Welsh";
var da = "Danish";
var de = "German";
var dv = "Maldivian";
var dz = "Dzongkha";
var ee = "Ewe";
var el = "Greek";
var en = "English";
var eo = "Esperanto";
var es = "Spanish";
var et = "Estonian";
var eu = "Basque";
var fa = "Persian";
var ff = "Fulah";
var fi = "Finnish";
var fj = "Fijian";
var fo = "Faroese";
var fr = "French";
var fy = "Western Frisian";
var ga = "Irish";
var gd = "Gaelic";
var gl = "Galician";
var gn = "Guarani";
var gu = "Gujarati";
var gv = "Manx";
var ha = "Hausa";
var he = "Hebrew";
var hi = "Hindi";
var ho = "Hiri Motu";
var hr = "Croatian";
var ht = "Haitian";
var hu = "Hungarian";
var hy = "Armenian";
var hz = "Herero";
var ia = "Interlingua";
var id = "Indonesian";
var ie = "Interlingue";
var ig = "Igbo";
var ii = "Sichuan Yi";
var ik = "Inupiaq";
var io = "Ido";
var is = "Icelandic";
var it = "Italian";
var iu = "Inuktitut";
var ja = "Japanese";
var jv = "Javanese";
var ka = "Georgian";
var kg = "Kongo";
var ki = "Kikuyu";
var kj = "Kuanyama";
var kk = "Kazakh";
var kl = "Kalaallisut";
var km = "Central Khmer";
var kn = "Kannada";
var ko = "Korean";
var kr = "Kanuri";
var ks = "Kashmiri";
var ku = "Kurdish";
var kv = "Komi";
var kw = "Cornish";
var ky = "Kirghiz";
var la = "Latin";
var lb = "Luxembourgish";
var lg = "Ganda";
var li = "Limburgan";
var ln = "Lingala";
var lo = "Lao";
var lt = "Lithuanian";
var lu = "Luba-Katanga";
var lv = "Latvian";
var mg = "Malagasy";
var mh = "Marshallese";
var mi = "Maori";
var mk = "Macedonian";
var ml = "Malayalam";
var mn = "Mongolian";
var mr = "Marathi";
var ms = "Malay";
var mt = "Maltese";
var my = "Burmese";
var na = "Nauru";
var nb = "Norwegian";
var nd = "North Ndebele";
var ne = "Nepali";
var ng = "Ndonga";
var nl = "Dutch";
var nn = "Norwegian";
var no = "Norwegian";
var nr = "South Ndebele";
var nv = "Navajo";
var ny = "Chichewa";
var oc = "Occitan";
var oj = "Ojibwa";
var om = "Oromo";
var or = "Oriya";
var os = "Ossetic";
var pa = "Panjabi";
var pi = "Pali";
var pl = "Polish";
var ps = "Pushto";
var pt = "Portuguese";
var qu = "Quechua";
var rm = "Romansh";
var rn = "Rundi";
var ro = "Romanian";
var ru = "Russian";
var rw = "Kinyarwanda";
var sa = "Sanskrit";
var sc = "Sardinian";
var sd = "Sindhi";
var se = "Northern Sami";
var sg = "Sango";
var si = "Sinhala";
var sk = "Slovak";
var sl = "Slovenian";
var sm = "Samoan";
var sn = "Shona";
var so = "Somali";
var sq = "Albanian";
var sr = "Serbian";
var ss = "Swati";
var st = "Sotho, Southern";
var su = "Sundanese";
var sv = "Swedish";
var sw = "Swahili";
var ta = "Tamil";
var te = "Telugu";
var tg = "Tajik";
var th = "Thai";
var ti = "Tigrinya";
var tk = "Turkmen";
var tl = "Tagalog";
var tn = "Tswana";
var to = "Tonga";
var tr = "Turkish";
var ts = "Tsonga";
var tt = "Tatar";
var tw = "Twi";
var ty = "Tahitian";
var ug = "Uighur";
var uk = "Ukrainian";
var ur = "Urdu";
var uz = "Uzbek";
var ve = "Venda";
var vi = "Vietnamese";
var vo = "Volapük";
var wa = "Walloon";
var wo = "Wolof";
var xh = "Xhosa";
var yi = "Yiddish";
var yo = "Yoruba";
var za = "Zhuang";
var zh = "Chinese";
var zu = "Zulu";
var codes = {
    aa: aa,
    ab: ab,
    ae: ae,
    af: af,
    ak: ak,
    am: am,
    an: an,
    ar: ar,
    as: as,
    av: av,
    ay: ay,
    az: az,
    ba: ba,
    be: be,
    bg: bg,
    bh: bh,
    bi: bi,
    bm: bm,
    bn: bn,
    bo: bo,
    br: br,
    bs: bs,
    ca: ca,
    ce: ce,
    ch: ch,
    co: co,
    cr: cr,
    cs: cs,
    cu: cu,
    cv: cv,
    cy: cy,
    da: da,
    de: de,
    dv: dv,
    dz: dz,
    ee: ee,
    el: el,
    en: en,
    eo: eo,
    es: es,
    et: et,
    eu: eu,
    fa: fa,
    ff: ff,
    fi: fi,
    fj: fj,
    fo: fo,
    fr: fr,
    fy: fy,
    ga: ga,
    gd: gd,
    gl: gl,
    gn: gn,
    gu: gu,
    gv: gv,
    ha: ha,
    he: he,
    hi: hi,
    ho: ho,
    hr: hr,
    ht: ht,
    hu: hu,
    hy: hy,
    hz: hz,
    ia: ia,
    id: id,
    ie: ie,
    ig: ig,
    ii: ii,
    ik: ik,
    io: io,
    is: is,
    it: it,
    iu: iu,
    ja: ja,
    jv: jv,
    ka: ka,
    kg: kg,
    ki: ki,
    kj: kj,
    kk: kk,
    kl: kl,
    km: km,
    kn: kn,
    ko: ko,
    kr: kr,
    ks: ks,
    ku: ku,
    kv: kv,
    kw: kw,
    ky: ky,
    la: la,
    lb: lb,
    lg: lg,
    li: li,
    ln: ln,
    lo: lo,
    lt: lt,
    lu: lu,
    lv: lv,
    mg: mg,
    mh: mh,
    mi: mi,
    mk: mk,
    ml: ml,
    mn: mn,
    mr: mr,
    ms: ms,
    mt: mt,
    my: my,
    na: na,
    nb: nb,
    nd: nd,
    ne: ne,
    ng: ng,
    nl: nl,
    nn: nn,
    no: no,
    nr: nr,
    nv: nv,
    ny: ny,
    oc: oc,
    oj: oj,
    om: om,
    or: or,
    os: os,
    pa: pa,
    pi: pi,
    pl: pl,
    ps: ps,
    pt: pt,
    qu: qu,
    rm: rm,
    rn: rn,
    ro: ro,
    ru: ru,
    rw: rw,
    sa: sa,
    sc: sc,
    sd: sd,
    se: se,
    sg: sg,
    si: si,
    sk: sk,
    sl: sl,
    sm: sm,
    sn: sn,
    so: so,
    sq: sq,
    sr: sr,
    ss: ss,
    st: st,
    su: su,
    sv: sv,
    sw: sw,
    ta: ta,
    te: te,
    tg: tg,
    th: th,
    ti: ti,
    tk: tk,
    tl: tl,
    tn: tn,
    to: to,
    tr: tr,
    ts: ts,
    tt: tt,
    tw: tw,
    ty: ty,
    ug: ug,
    uk: uk,
    ur: ur,
    uz: uz,
    ve: ve,
    vi: vi,
    vo: vo,
    wa: wa,
    wo: wo,
    xh: xh,
    yi: yi,
    yo: yo,
    za: za,
    zh: zh,
    zu: zu
};

function isISO639LanguageCode(input) {
    return hasOwnProperty(codes, input);
}
function isBCP47LanguageCode(input) {
    const hyphenIndex = input.indexOf('-');
    if (hyphenIndex !== -1) {
        input = input.substring(0, hyphenIndex);
    }
    return isISO639LanguageCode(input);
}

function parseGetArguments(...input) {
    if (input.length === 3) {
        const [key, data, context] = input;
        if (typeof context === 'string') {
            if (isBCP47LanguageCode(context)) {
                const parsed = parseKey(key);
                return {
                    ...data ? {
                        data
                    } : {},
                    group: parsed[0],
                    key: parsed[1],
                    locale: context
                };
            }
            return {
                ...data ? {
                    data
                } : {},
                group: context,
                key
            };
        }
        let locale;
        let group;
        if (isGroupContext(context)) {
            group = context.group;
        }
        if (isLocaleContext(context)) {
            locale = context.locale;
        }
        if (group) {
            return {
                ...data ? {
                    data
                } : {},
                group,
                key,
                locale
            };
        }
    }
    if (input.length >= 1) {
        const [groupKey, data] = input;
        if (isObject(data)) {
            if (isGroupContext(data) || isLocaleContext(data)) {
                let locale;
                let group;
                if (isGroupContext(data)) {
                    group = data.group;
                }
                if (isLocaleContext(data)) {
                    locale = data.locale;
                }
                if (group) {
                    return {
                        group,
                        locale,
                        key: groupKey
                    };
                }
                const parsed = parseKey(groupKey);
                return {
                    group: parsed[0],
                    locale,
                    key: parsed[1]
                };
            }
            const [group, key] = parseKey(groupKey);
            return {
                ...data ? {
                    data
                } : {},
                group,
                key
            };
        }
        let locale;
        let group;
        if (typeof data === 'string') {
            if (isBCP47LanguageCode(data)) {
                locale = data;
            } else {
                group = data;
            }
        }
        if (typeof group === 'undefined') {
            const parsed = parseKey(groupKey);
            return {
                group: parsed[0],
                ...locale ? {
                    locale
                } : {},
                key: parsed[1]
            };
        }
        return {
            group,
            ...locale ? {
                locale
            } : {},
            key: groupKey
        };
    }
    return undefined;
}

function flattenLinesRecord(input, prefix = '') {
    const output = {};
    const keys = Object.keys(input);
    for(let i = 0; i < keys.length; i++){
        const value = input[keys[i]];
        if (typeof value === 'string') {
            if (prefix) {
                output[`${prefix}.${keys[i]}`] = value;
            } else {
                output[keys[i]] = value;
            }
        } else {
            assign(output, flattenLinesRecord(value, prefix ? `${prefix}.${keys[i]}` : keys[i]));
        }
    }
    return output;
}

function buildOutputForLines(input, lines) {
    const output = [];
    const data = flattenLinesRecord(lines);
    const lineKeys = Object.keys(data);
    for(let i = 0; i < lineKeys.length; i++){
        output.push({
            ...input,
            key: lineKeys[i],
            value: data[lineKeys[i]]
        });
    }
    return output;
}
function parseSetArguments(...input) {
    if (input.length === 3) {
        const [key, value, context] = input;
        // todo: verify key & value are of type string
        if (isGroupContext(context) && isLocaleContext(context)) {
            return [
                {
                    group: context.group,
                    locale: context.locale,
                    key,
                    value
                }
            ];
        }
        if (isLocaleContext(context)) {
            const parsed = parseKey(key);
            return [
                {
                    group: parsed[0],
                    locale: context.locale,
                    key: parsed[1],
                    value
                }
            ];
        }
        return [];
    }
    if (input.length === 2) {
        const [keyOrRecord, data] = input;
        if (typeof keyOrRecord === 'string' && typeof data === 'string') {
            const [group, key] = parseKey(keyOrRecord);
            return [
                {
                    group,
                    key,
                    value: data
                }
            ];
        }
        if (isObject(keyOrRecord)) {
            if (isLocaleContext(data) && !isGroupContext(data)) {
                const output = [];
                const keys = Object.keys(keyOrRecord);
                for(let i = 0; i < keys.length; i++){
                    output.push(...buildOutputForLines({
                        locale: typeof data === 'string' ? data : data.locale,
                        group: keys[i]
                    }, keyOrRecord[keys[i]]));
                }
                return output;
            }
            if (isGroupContext(data)) {
                let locale;
                if (isLocaleContext(data)) {
                    locale = data.locale;
                }
                return buildOutputForLines({
                    locale,
                    group: data.group
                }, keyOrRecord);
            }
            if (typeof data === 'string') {
                if (isBCP47LanguageCode(data)) {
                    const output = [];
                    const keys = Object.keys(keyOrRecord);
                    for(let i = 0; i < keys.length; i++){
                        output.push(...buildOutputForLines({
                            group: keys[i]
                        }, keyOrRecord[keys[i]]));
                    }
                    return output;
                }
                return buildOutputForLines({
                    group: data
                }, keyOrRecord);
            }
        }
        if (typeof keyOrRecord === 'string') {
            const parsed = parseKey(keyOrRecord);
            if (typeof data === 'string') {
                return [
                    {
                        group: parsed[0],
                        key: parsed[1],
                        value: data
                    }
                ];
            }
            if (isObject(data)) {
                return buildOutputForLines({
                    group: parsed[0]
                }, data);
            }
        }
    }
    if (input.length === 1) {
        const data = input[0];
        const keys = Object.keys(data);
        if (keys.length === 0) {
            return [];
        }
        const output = [];
        const key = keys[0];
        if (isBCP47LanguageCode(key)) {
            for(let i = 0; i < keys.length; i++){
                const groupKeys = Object.keys(data[keys[i]]);
                for(let j = 0; j < groupKeys.length; j++){
                    output.push(...buildOutputForLines({
                        locale: keys[i],
                        group: groupKeys[j]
                    }, data[keys[i]][groupKeys[j]]));
                }
            }
        } else {
            for(let i = 0; i < keys.length; i++){
                output.push(...buildOutputForLines({
                    group: keys[i]
                }, data[keys[i]]));
            }
        }
        return output;
    }
    return [];
}

function setObjectPathProperty(record, key, value) {
    const parts = key.split('.');
    if (parts.length === 1) {
        record[key] = value;
        return;
    }
    const prefix = parts.shift();
    if (prefix) {
        if (!Object.prototype.hasOwnProperty.call(record, prefix) || !isObject(record[prefix])) {
            record[prefix] = {};
        }
        setObjectPathProperty(record[prefix], parts.join('.'), value);
    }
}
function getObjectPathProperty(data, key) {
    const dotIndex = key.indexOf('.');
    const currentKey = dotIndex === -1 ? key : key.substring(0, dotIndex);
    if (dotIndex === -1) {
        return data[currentKey];
    }
    if (!isObject(data[currentKey])) {
        return undefined;
    }
    const nextKey = key.substring(currentKey.length + 1);
    return getObjectPathProperty(data[currentKey], nextKey);
}

/*
 * Copyright (c) 2023.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ function template(str, data, regex = /\{\{(.+?)\}\}/g) {
    return Array.from(str.matchAll(regex)).reduce((acc, match)=>{
        if (typeof data[match[1]] !== 'undefined') {
            return acc.replace(match[0], data[match[1]]);
        }
        return acc;
    }, str);
}

class MemoryStore {
    async get(context) {
        return this.getSync(context);
    }
    getSync(context) {
        if (!this.data[context.locale] || !this.data[context.locale][context.group]) {
            return undefined;
        }
        const output = getObjectPathProperty(this.data[context.locale][context.group], context.key);
        if (typeof output === 'string') {
            return output;
        }
        return undefined;
    }
    async set(context) {
        this.setSync(context);
    }
    setSync(context) {
        this.initLines(context.group, context.locale);
        setObjectPathProperty(this.data[context.locale][context.group], context.key, context.value);
    }
    initLines(group, locale) {
        if (typeof this.data[locale] === 'undefined') {
            this.data[locale] = {};
        }
        if (typeof this.data[locale][group] === 'undefined') {
            this.data[locale][group] = {};
        }
    }
    constructor(){
        this.data = {};
    }
}

function buildConfig(input) {
    input = input || {};
    return {
        locale: input.locale || LOCALE_DEFAULT,
        data: input.data || {},
        store: input.store || new MemoryStore()
    };
}

class Ilingo {
    // ----------------------------------------------------
    setLocale(key) {
        this.locale = key;
    }
    resetLocale() {
        this.locale = LOCALE_DEFAULT;
    }
    getLocale() {
        return this.locale;
    }
    async set(...input) {
        const parsed = parseSetArguments(...input);
        const promises = [];
        for(let i = 0; i < parsed.length; i++){
            promises.push(this.store.set({
                ...parsed[i],
                locale: parsed[i].locale || this.getLocale()
            }));
        }
        await Promise.all(promises);
    }
    setSync(...input) {
        const parsed = parseSetArguments(...input);
        for(let i = 0; i < parsed.length; i++){
            this.store.setSync({
                ...parsed[i],
                locale: parsed[i].locale || this.getLocale()
            });
        }
    }
    async get(...input) {
        const parsed = parseGetArguments(...input);
        if (!parsed) {
            return undefined;
        }
        const message = await this.store.get({
            locale: parsed.locale || this.getLocale(),
            group: parsed.group,
            key: parsed.key
        });
        return this.format(message || parsed.key, parsed.data || {});
    }
    getSync(...input) {
        const parsed = parseGetArguments(...input);
        if (!parsed) {
            return undefined;
        }
        const message = this.store.getSync({
            locale: parsed.locale || this.getLocale(),
            group: parsed.group,
            key: parsed.key
        });
        return this.format(message || parsed.key, parsed.data || {});
    }
    // ----------------------------------------------------
    format(input, data) {
        return template(input, data || {});
    }
    // ----------------------------------------------------
    constructor(input){
        const config = buildConfig(input);
        this.locale = config.locale;
        this.store = config.store;
        this.setSync(config.data);
    }
}

let instance;
function useIlingo() {
    if (typeof instance !== 'undefined') {
        return instance;
    }
    instance = new Ilingo();
    return instance;
}
function setIlingo(input) {
    instance = input;
}
function unsetIlingo() {
    instance = undefined;
}

async function lang(...input) {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    return useIlingo().get(...input);
}
function langSync(...input) {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    return useIlingo().getSync(...input);
}

const ilingo = useIlingo();

export { Ilingo, MemoryStore, buildConfig, ilingo as default, getObjectPathProperty, isBCP47LanguageCode, isGroupContext, isISO639LanguageCode, isLineRecord, isLocaleContext, lang, langSync, parseGetArguments, parseKey, parseSetArguments, setIlingo, setObjectPathProperty, template, unsetIlingo, useIlingo };
//# sourceMappingURL=index.mjs.map
