import { _serialize, serializeQuery } from './client.js';
import _isEqual from 'lodash/isEqual.js';
export const minilinksQuery = (query, ml) => {
    if (typeof (query) === 'number' || typeof (query) === 'string')
        return [ml.byId[query]];
    else {
        const q = serializeQuery(query, 'links');
        const result = minilinksQueryHandle(q.where, ml);
        return q.limit ? result.slice(q.offset || 0, (q.offset || 0) + (q.limit)) : result;
    }
};
export const minilinksQueryIs = (query, link) => {
    if (typeof (query) === 'number')
        return link.id === query;
    else {
        const q = serializeQuery(query, 'links');
        return minilinksQueryLevel(q, link, 'links');
    }
};
export const expToSets = (ml, exp, sets, list, toArray = false) => {
    if ((exp === null || exp === void 0 ? void 0 : exp._eq) && (list === null || list === void 0 ? void 0 : list[exp === null || exp === void 0 ? void 0 : exp._eq]))
        sets.push(toArray ? [list[exp === null || exp === void 0 ? void 0 : exp._eq]] : list[exp === null || exp === void 0 ? void 0 : exp._eq]);
    if (exp === null || exp === void 0 ? void 0 : exp._in)
        sets.push(...(toArray ? exp._in.map(id => (list === null || list === void 0 ? void 0 : list[id]) ? [list[id]] : []) : exp._in.map(id => list[id])));
};
export const multiExpToSets = (ml, exp, sets, list, key, toArray = false) => {
    var _a;
    if (typeof (exp) === 'object') {
        if (Array.isArray(exp))
            exp.map((exp) => multiExpToSets(ml, exp, sets, list, key));
        else {
            const links = minilinksQueryHandle(exp, ml);
            for (let l = 0; l < links.length; l++) {
                sets.push(toArray ? ((list === null || list === void 0 ? void 0 : list[(_a = links === null || links === void 0 ? void 0 : links[l]) === null || _a === void 0 ? void 0 : _a[key]]) ? [list[links[l][key]]] : []) : list[links[l][key]]);
            }
        }
    }
};
export const findSets = (ml, q, sets) => {
    if (typeof (q) === 'object') {
        if (Array.isArray(q)) {
            q.map((q) => findSets(ml, q, sets));
        }
        else {
            if (q === null || q === void 0 ? void 0 : q.id)
                expToSets(ml, q === null || q === void 0 ? void 0 : q.id, sets, ml.byId, true);
            if (q === null || q === void 0 ? void 0 : q.type_id)
                expToSets(ml, q === null || q === void 0 ? void 0 : q.type_id, sets, ml.byType);
            if (q === null || q === void 0 ? void 0 : q.from_id)
                expToSets(ml, q === null || q === void 0 ? void 0 : q.from_id, sets, ml.byFrom);
            if (q === null || q === void 0 ? void 0 : q.to_id)
                expToSets(ml, q === null || q === void 0 ? void 0 : q.to_id, sets, ml.byTo);
            if (q._and)
                findSets(ml, q._and, sets);
            if (!sets.length) {
                if (q._or)
                    findSets(ml, q._or, sets);
                if (q === null || q === void 0 ? void 0 : q.in)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.in, sets, ml.byId, 'to_id', true);
                if (q === null || q === void 0 ? void 0 : q.out)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.out, sets, ml.byId, 'from_id', true);
                if (q === null || q === void 0 ? void 0 : q.typed)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.typed, sets, ml.byId, 'type_id', true);
                if (q === null || q === void 0 ? void 0 : q.to)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.to, sets, ml.byTo, 'id');
                if (q === null || q === void 0 ? void 0 : q.from)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.from, sets, ml.byFrom, 'id');
                if (q === null || q === void 0 ? void 0 : q.type)
                    multiExpToSets(ml, q === null || q === void 0 ? void 0 : q.type, sets, ml.byType, 'id');
            }
        }
    }
};
export const minilinksQueryHandle = (q, ml) => {
    let sets = [];
    findSets(ml, q, sets);
    if (!sets.length)
        sets = [ml.links];
    const results = [];
    const ids = {};
    for (let s in sets) {
        for (let l = 0; l < sets[s].length; l++) {
            const link = sets[s][l];
            if (ids[link.id])
                continue;
            ids[link.id] = true;
            const r = minilinksQueryLevel(q, link, 'links');
            if (r)
                results.push(link);
        }
    }
    return results;
};
export const minilinksQueryLevel = (q, link, env = 'links') => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
    const fields = Object.keys(q);
    if (env === 'links') {
        if (!link)
            return false;
        for (const f in fields) {
            const field = fields[f];
            if (field === '_and') {
                for (const a in q[field]) {
                    if (!minilinksQueryLevel(q[field][a], link, env)) {
                        return false;
                    }
                }
            }
            else if (field === '_or') {
                let oneOf = false;
                for (const a in q[field]) {
                    if (minilinksQueryLevel(q[field][a], link, env)) {
                        oneOf = true;
                        break;
                    }
                }
                if (!oneOf)
                    return false;
            }
            else if (field === '_not') {
                if (minilinksQueryLevel(q[field], link, env)) {
                    return false;
                }
            }
            else if ((_b = (_a = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _a === void 0 ? void 0 : _a.fields) === null || _b === void 0 ? void 0 : _b[field]) {
                if ((_d = (_c = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _c === void 0 ? void 0 : _c.virtualize) === null || _d === void 0 ? void 0 : _d[field]) {
                    let isValid = false;
                    for (const a in (_f = (_e = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _e === void 0 ? void 0 : _e.virtualize) === null || _f === void 0 ? void 0 : _f[field]) {
                        const alias = (_h = (_g = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _g === void 0 ? void 0 : _g.virtualize) === null || _h === void 0 ? void 0 : _h[field][a];
                        if (minilinksQueryComparison(q, link, field, alias, env))
                            isValid = true;
                    }
                    if (!isValid)
                        return false;
                }
                else {
                    if (!minilinksQueryComparison(q, link, field, field, env)) {
                        return false;
                    }
                }
            }
            else {
                if (((_k = (_j = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _j === void 0 ? void 0 : _j.relations) === null || _k === void 0 ? void 0 : _k[field]) === 'links') {
                    if (typeof (q[field]) === 'object') {
                        if (typeof (q[field].length) === 'number' || typeof (q[field].length) === 'string') {
                            if (!q[field].length)
                                return false;
                            let found = false;
                            for (const sub in link === null || link === void 0 ? void 0 : link[field]) {
                                const sublink = link === null || link === void 0 ? void 0 : link[field][sub];
                                if (minilinksQueryLevel(q[field], sublink, env)) {
                                    found = true;
                                    break;
                                }
                            }
                            if (!found)
                                return false;
                        }
                        else {
                            if (Array.isArray(link === null || link === void 0 ? void 0 : link[field])) {
                                let found = false;
                                for (const el in link === null || link === void 0 ? void 0 : link[field]) {
                                    if (minilinksQueryLevel(q[field], link === null || link === void 0 ? void 0 : link[field][el], env)) {
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found)
                                    return false;
                            }
                            else {
                                if (!minilinksQueryLevel(q[field], link === null || link === void 0 ? void 0 : link[field], env)) {
                                    return false;
                                }
                            }
                        }
                    }
                }
                else if (['value', 'strings', 'numbers', 'objects'].includes((_m = (_l = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _l === void 0 ? void 0 : _l.relations) === null || _m === void 0 ? void 0 : _m[field])) {
                    if (!(link === null || link === void 0 ? void 0 : link[field]) || !minilinksQueryLevel(q[field], link === null || link === void 0 ? void 0 : link[field], 'value')) {
                        return false;
                    }
                }
                else {
                    return false;
                }
            }
        }
    }
    else if (env === 'value') {
        for (const f in fields) {
            const field = fields[f];
            if ((_p = (_o = _serialize === null || _serialize === void 0 ? void 0 : _serialize[env]) === null || _o === void 0 ? void 0 : _o.fields) === null || _p === void 0 ? void 0 : _p[field]) {
                if (!minilinksQueryComparison(q, link, field, field, env)) {
                    return false;
                }
            }
            else {
                return false;
            }
        }
    }
    else {
        return false;
    }
    return true;
};
var like = (q, v) => {
    var _a, _b, _c;
    if (!v)
        return false;
    var p = q.split('%');
    if ((p === null || p === void 0 ? void 0 : p[0]) === '')
        p = p === null || p === void 0 ? void 0 : p.slice(1);
    if (p[p.length - 1] === '')
        p = p === null || p === void 0 ? void 0 : p.slice(0, p.length - 1);
    var _v = v;
    let i = 0;
    if (q[i] !== '%') {
        if (_v.slice(0, ((_a = p === null || p === void 0 ? void 0 : p[i]) === null || _a === void 0 ? void 0 : _a.length) - 1) !== (p === null || p === void 0 ? void 0 : p[i]))
            return false;
        _v = _v.slice(((_b = p === null || p === void 0 ? void 0 : p[i]) === null || _b === void 0 ? void 0 : _b.length) - 1);
        i++;
    }
    for (; i < (p === null || p === void 0 ? void 0 : p.length); i++) {
        const f = _v.indexOf(p === null || p === void 0 ? void 0 : p[i]);
        if (!~f)
            return false;
        _v = _v.slice(f + ((_c = p === null || p === void 0 ? void 0 : p[i]) === null || _c === void 0 ? void 0 : _c.length) - 1);
    }
    return true;
};
export const minilinksQueryComparison = (q, link, field, alias, env = 'links') => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
    const comp = q === null || q === void 0 ? void 0 : q[field];
    if (typeof (comp) === 'undefined')
        throw new Error(`${field} === undefined`);
    if (env === 'links' && typeof (link === null || link === void 0 ? void 0 : link[alias]) === 'object' && Array.isArray(link === null || link === void 0 ? void 0 : link[alias])) {
        if (comp.hasOwnProperty('_eq')) {
            if (!(link === null || link === void 0 ? void 0 : link[alias].includes(comp._eq)))
                return false;
        }
        if (comp.hasOwnProperty('_neq')) {
            if (link === null || link === void 0 ? void 0 : link[alias].includes(comp._neq))
                return false;
        }
    }
    else {
        if (comp.hasOwnProperty('_is_null')) {
            if ((((link === null || link === void 0 ? void 0 : link[alias]) === null) || typeof (link === null || link === void 0 ? void 0 : link[alias]) === 'undefined') !== comp._is_null)
                return false;
        }
        else {
            if (typeof (link === null || link === void 0 ? void 0 : link[alias]) === 'undefined')
                return false;
        }
        if (comp.hasOwnProperty('_eq')) {
            if (env === 'links' && (link === null || link === void 0 ? void 0 : link[alias]) !== comp._eq)
                return false;
            if (env === 'value' && !_isEqual(link === null || link === void 0 ? void 0 : link[alias], comp._eq))
                return false;
        }
        if (comp.hasOwnProperty('_neq')) {
            if (env === 'links' && (link === null || link === void 0 ? void 0 : link[alias]) === comp._neq)
                return false;
            if (env === 'value' && _isEqual(link === null || link === void 0 ? void 0 : link[alias], comp._neq))
                return false;
        }
        if (comp.hasOwnProperty('_gt')) {
            if (!((link === null || link === void 0 ? void 0 : link[alias]) > comp._gt))
                return false;
        }
        if (comp.hasOwnProperty('_gte')) {
            if (!((link === null || link === void 0 ? void 0 : link[alias]) >= comp._gte))
                return false;
        }
        if (comp.hasOwnProperty('_lt')) {
            if (!((link === null || link === void 0 ? void 0 : link[alias]) < comp._lt))
                return false;
        }
        if (comp.hasOwnProperty('_lte')) {
            if (!((link === null || link === void 0 ? void 0 : link[alias]) <= comp._lte))
                return false;
        }
        if (comp.hasOwnProperty('_in')) {
            if (!((_a = comp === null || comp === void 0 ? void 0 : comp._in) === null || _a === void 0 ? void 0 : _a.includes(link === null || link === void 0 ? void 0 : link[alias])))
                return false;
        }
        if (comp.hasOwnProperty('_nin')) {
            if ((_b = comp === null || comp === void 0 ? void 0 : comp._nin) === null || _b === void 0 ? void 0 : _b.includes(link === null || link === void 0 ? void 0 : link[alias]))
                return false;
        }
        if (comp.hasOwnProperty('_ilike')) {
            if (!((_c = link === null || link === void 0 ? void 0 : link[alias]) === null || _c === void 0 ? void 0 : _c.toLowerCase) || !like((_d = comp === null || comp === void 0 ? void 0 : comp._ilike) === null || _d === void 0 ? void 0 : _d.toLowerCase(), (_e = link === null || link === void 0 ? void 0 : link[alias]) === null || _e === void 0 ? void 0 : _e.toLowerCase()))
                return false;
        }
        if (comp.hasOwnProperty('_nilike')) {
            if (!(!((_f = link === null || link === void 0 ? void 0 : link[alias]) === null || _f === void 0 ? void 0 : _f.toLowerCase) || !like((_g = comp === null || comp === void 0 ? void 0 : comp._nilike) === null || _g === void 0 ? void 0 : _g.toLowerCase(), (_h = link === null || link === void 0 ? void 0 : link[alias]) === null || _h === void 0 ? void 0 : _h.toLowerCase())))
                return false;
        }
        if (comp.hasOwnProperty('_like')) {
            if (!like(comp === null || comp === void 0 ? void 0 : comp._like, link === null || link === void 0 ? void 0 : link[alias]))
                return false;
        }
        if (comp.hasOwnProperty('_nlike')) {
            if (like(comp === null || comp === void 0 ? void 0 : comp._nlike, link === null || link === void 0 ? void 0 : link[alias]))
                return false;
        }
        if (comp.hasOwnProperty('_iregex')) {
            if (!((_j = link === null || link === void 0 ? void 0 : link[alias]) === null || _j === void 0 ? void 0 : _j.toLowerCase) || !((_k = link === null || link === void 0 ? void 0 : link[alias]) === null || _k === void 0 ? void 0 : _k.toLowerCase().match(comp === null || comp === void 0 ? void 0 : comp._iregex)))
                return false;
        }
        if (comp.hasOwnProperty('_regex')) {
            if (!(link === null || link === void 0 ? void 0 : link[alias].match(comp === null || comp === void 0 ? void 0 : comp._regex)))
                return false;
        }
        if (comp.hasOwnProperty('_niregex')) {
            if (!((_l = link === null || link === void 0 ? void 0 : link[alias]) === null || _l === void 0 ? void 0 : _l.toLowerCase) || !((_m = link === null || link === void 0 ? void 0 : link[alias]) === null || _m === void 0 ? void 0 : _m.toLowerCase().match(comp === null || comp === void 0 ? void 0 : comp._niregex)))
                return false;
        }
        if (comp.hasOwnProperty('_nregex')) {
            if (!(link === null || link === void 0 ? void 0 : link[alias].match(comp === null || comp === void 0 ? void 0 : comp._nregex)))
                return false;
        }
        return true;
    }
};
//# sourceMappingURL=minilinks-query.js.map