import { read_property } from "../../../core/model/object/read_property.js";

/**
 *
 * @param {number} entity
 * @param {EntityComponentDataset} ecd
 * @param {string} path
 */
function resolvePath(entity, ecd, path) {
    if (!ecd.entityExists(entity)) {
        // entity doesn't exist
        return undefined;
    }

    const parts = path.split('.');


    const part_count = parts.length;

    if (part_count < 1) {
        return undefined;
    }

    const componentName = parts[0];

    const ComponentClass = ecd.getComponentClassByName(componentName);

    if (ComponentClass === null) {
        // no component of such class registered
        return undefined;
    }

    const component = ecd.getComponent(entity, ComponentClass);

    if (component === undefined) {
        // component not present on entity
        return undefined;
    }

    return read_property(component, parts, 1, part_count - 1);
}

export class EntityProxyScope {

    constructor() {

        /**
         *
         * @type {number}
         */
        this.entity = -1;

        /**
         *
         * @type {EntityComponentDataset}
         */
        this.ecd = null;

        this.scope = new Proxy(this, {
            get(target, p, receiver) {

                const ecd = target.ecd;
                const entity = target.entity;

                return resolvePath(entity, ecd, p);
            },
            set(target, p, value, receiver) {

                const v = resolvePath(target.entity, target.ecd, p);

                if (v === undefined) {
                    throw new Error(`Path ${p} could not be resolved`);
                }

                const type = typeof v;
                if (type === "object" && typeof v.set === "function") {
                    v.set(value);
                    return true;
                } else {
                    throw new Error(`Terminal property '${p}' is of wrong type`);
                }
            }
        });
    }

    /**
     *
     * @param {number} entity
     * @param {EntityComponentDataset} ecd
     */
    attach(entity, ecd) {
        this.entity = entity;
        this.ecd = ecd;
    }

}
