"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.proxy = proxy;
exports.interfaceFilters = interfaceFilters;
exports.proxyWrap = proxyWrap;
const id_1 = require("./client/id");
const method_1 = require("./client/method");
const _map_1 = require("./constant/$map");
const object_1 = require("./util/object");
function proxy(obj, filters) {
    let stop_event = undefined;
    let stop_depth = 0;
    function attach(obj, filters, depth) {
        const { call, watch, ref } = filters;
        return new Proxy(obj, {
            get: (target, name) => {
                if (name === '__wrapped') {
                    return true;
                }
                const value = target[name];
                if (call.has(name)) {
                    return (...args) => {
                        stop_event = (0, id_1.camelToSnake)(name.slice(1));
                        stop_depth = depth;
                        return value.call(target, ...args);
                    };
                }
                else if (watch.has(name)) {
                    return (data, callback) => {
                        return value.call(target, data, (moment) => {
                            const { event } = moment;
                            const path = moment.data?.path;
                            if (path) {
                                if (stop_event) {
                                    if (!call.has(`$${(0, id_1.snakeToCamel)(event)}`)) {
                                        callback(moment);
                                        return;
                                    }
                                    if (stop_event === event) {
                                        if (path.length === stop_depth) {
                                            stop_event = undefined;
                                            stop_depth = 0;
                                        }
                                    }
                                    else {
                                        //
                                    }
                                }
                                else {
                                    callback(moment);
                                }
                            }
                            else {
                                if (stop_event) {
                                    if (stop_event === event && stop_depth === depth) {
                                        stop_event = undefined;
                                        return;
                                    }
                                }
                                callback(moment);
                            }
                        });
                    };
                }
                else if (ref.has(name)) {
                    return (data) => {
                        const { detached = true, __ } = data;
                        stop_depth = depth + 1;
                        const $ref = value.call(target, data);
                        if ($ref.__wrapped) {
                            return $ref;
                        }
                        const filters = interfaceFilters(__);
                        if (detached) {
                            return proxy($ref, filters);
                        }
                        else {
                            return attach($ref, filters, depth + 1);
                        }
                    };
                }
                return value;
            },
        });
    }
    return attach(obj, filters, 0);
}
const $set = (array) => {
    return new Set(array.map(_map_1.$map));
};
const ASYNC_FILTER = (0, object_1.mapObjKV)(method_1.METHOD, (__, filter) => (0, object_1.mapObjVK)(filter, $set));
const _interface_filter_cache = {};
function interfaceFilters(_ = []) {
    const id = _.sort().join('-');
    let filter = _interface_filter_cache[id];
    if (filter) {
        return filter;
    }
    filter = {
        get: new Set(),
        call: new Set(),
        watch: new Set(),
        ref: new Set(),
    };
    for (const __ of ['$', ..._]) {
        for (const type of method_1.METHOD_TYPES) {
            const FILTER = ASYNC_FILTER[__][type];
            for (const name of FILTER) {
                filter[type].add(name);
            }
        }
    }
    _interface_filter_cache[id] = filter;
    return filter;
}
function proxyWrap(obj, _ = []) {
    const filters = interfaceFilters(_);
    return proxy(obj, filters);
}
//# sourceMappingURL=proxyWrap.js.map