import { EventDetails, ScryptedInterface, ScryptedUserAccessControl } from "@scrypted/types";

/**
 * Scrypted Access Controls allow selective reading of state, subscription to evemts,
 * and invocation of methods.
 * Everything else should be rejected.
 */
export class AccessControls {
    constructor(public acl: ScryptedUserAccessControl) {
    }

    deny(reason: string = 'User does not have permission') {
        throw new Error(reason);
    }

    shouldRejectDevice(id: string) {
        if (this.acl.devicesAccessControls === null)
            return false;

        if (!this.acl.devicesAccessControls)
            return true;

        const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
        return !dacls.length;
    }

    shouldRejectProperty(id: string, property: string) {
        if (this.acl.devicesAccessControls === null)
            return false;

        if (!this.acl.devicesAccessControls)
            return true;

        const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);

        for (const dacl of dacls) {
            if (!dacl.properties || dacl.properties.includes(property))
                return false;
        }

        return true;
    }

    shouldRejectEvent(id: string, eventDetails: EventDetails) {
        if (this.acl.devicesAccessControls === null)
            return false;

        if (!this.acl.devicesAccessControls)
            return true;

        const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);

        const { property } = eventDetails;
        if (property) {
            for (const dacl of dacls) {
                if (!dacl.properties || dacl.properties.includes(property))
                    return false;
            }
        }

        const { eventInterface } = eventDetails;

        for (const dacl of dacls) {
            if (!dacl.interfaces || dacl.interfaces.includes(eventInterface))
                return false;
        }

        return true;
    }

    shouldRejectInterface(id: string, scryptedInterface: ScryptedInterface) {
        if (this.acl.devicesAccessControls === null)
            return false;

        if (!this.acl.devicesAccessControls)
            return true;

        const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);

        for (const dacl of dacls) {
            if (!dacl.interfaces || dacl.interfaces.includes(scryptedInterface))
                return false;
        }

        return true;
    }

    shouldRejectMethod(id: string, method: string) {
        if (this.acl.devicesAccessControls === null)
            return false;

        if (!this.acl.devicesAccessControls)
            return true;

        const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);

        for (const dacl of dacls) {
            if (!dacl.methods || dacl.methods.includes(method))
                return false;
        }

        return true;
    }
}