import { type RoomUser, type UserManager } from "@netless/forge-room";
import EventEmitter from "eventemitter3";
import * as Y from "yjs";

export enum ForgeSlidePermissionFlag {
    /**
     * 没有任何权限, 只能同步他人的操作
     */
    none = 0b0000000000000000,
    /**
     * 可以操作上一步下一步动画
     */
    changeStep = 0b0000000000000001,
    /**
     * 可以切面页码
     */
    changePage = 0b0000000000000010,
    /**
     * 可以触发点击动画
     */
    clickAnim = 0b0000000000000100,
    /**
     * 拥有所有权限
     */
    all = ForgeSlidePermissionFlag.changePage |
        ForgeSlidePermissionFlag.changeStep |
        ForgeSlidePermissionFlag.clickAnim
}

export interface ForgeSlidePermissionEvents {
    /**
     * 当用户权限变更时触发
     * @param { string } userId 对应 userId
     * @param { ForgeSlidePermissionFlag[] } flags 当前权限列表
     * @param { number } value 权限值
     */
    change: (userId: string, flags: ForgeSlidePermissionFlag[], value: number) => void;
}

export class ForgeSlidePermissions extends EventEmitter<ForgeSlidePermissionEvents> {

    private requestUserMap: (userId: string) => Y.Map<any>;
    private userManager: UserManager;
    private observers: Map<string, any> = new Map();

    public constructor(
        userManager: UserManager,
        requestUserMap: (userId: string) => Y.Map<any>,
    ) {
        super();
        this.userManager = userManager;
        this.requestUserMap = requestUserMap;
        this.createModel(this.userManager.selfId);
        this.userManager.userIdList().forEach((userId) => {
            this.addObserve(userId);
        });

        this.userManager.on("join", this.handleUserJoin);
        this.userManager.on("leave", this.handleUserLeave);
    }

    private handleUserLeave = (user: RoomUser) => {
        const cb = this.observers.get(user.id);
        if (cb) {
            this.requestUserMap(user.id).unobserve(cb);
        }
    };

    private handleUserJoin = (user: RoomUser) => {
        this.addObserve(user.id);
    };

    private addObserve(userId: string) {
        const observer = (evt: Y.YMapEvent<any>) => {
            this.handleUserPermissionChange(userId, evt);
        };
        this.observers.set(userId, observer);
        this.requestUserMap(userId).observe(observer)
    }

    private createModel(userId: string) {
        const userMap = this.requestUserMap(userId);
        if (!userMap.has("permission")) {
            userMap.set("permission", 0);
        }
    }

    private handleUserPermissionChange(userId: string, evt: Y.YMapEvent<any>) {
        for (const [key, value] of evt.changes.keys.entries()) {
            if (key === "permission") {
                if (value.action === "add" || value.action === "update") {
                    const newValue = this.requestUserMap(userId).get("permission");
                    this.emit("change", userId, this.resolveFlags(newValue), newValue);
                }
            }
        }
    }

    /**
     * 解析权限列表组合
     * @param {number} value - 权限数字值
     * @return {WhiteboardPermissionFlag[]} - 权限列表
     */
    public resolveFlags(value: number): ForgeSlidePermissionFlag[] {
        return [
            ForgeSlidePermissionFlag.changePage,
            ForgeSlidePermissionFlag.changeStep,
            ForgeSlidePermissionFlag.clickAnim
        ].filter(v => (v & value) !== 0)
    }

    /**
     * 获取权限列表组合对应的数值
     * @param { string } userId 不传表示获取自己
     */
    public getPermissionValue(userId?: string): number {
        return this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0;
    }

    /**
     * 获取权限列表
     * @param {string=} userId 可选, 不传表示获取自己
     */
    public getPermissionFlags(userId?: string): ForgeSlidePermissionFlag[] {
        const value = this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0;
        return this.resolveFlags(value);
    }

    /**
     * 返回对应 userId 是否有相应权限
     * @param {string=} userId 可选, 不传表示返回自己是否有相应权限
     * @param {WhiteboardPermissionFlag} flag
     */
    public hasPermission(flag: ForgeSlidePermissionFlag, userId?: string): boolean {
        return ((this.requestUserMap(userId ?? this.userManager.selfId).get("permission") ?? 0) & flag) !== 0;
    }

    /**
     * 添加权限
     * @param {WhiteboardPermissionFlag} flag 权限标记
     * @param {string=} userId 可选, 为 userId 添加权限, 不传表示为自己添加权限
     */
    public addPermission(flag: ForgeSlidePermissionFlag, userId?: string) {
        const userMap = this.requestUserMap(userId ?? this.userManager.selfId);
        const oldValue = userMap.get("permission") ?? 0;
        this.requestUserMap(userId ?? this.userManager.selfId).set("permission", oldValue | flag);
    }

    /**
     * 移除权限
     * @param {WhiteboardPermissionFlag} flag 权限标记
     * @param {string=} userId 可选, 为 userId 移除权限, 不传表示为自己移除权限
     */
    public removePermission(flag: ForgeSlidePermissionFlag, userId?: string) {
        const userMap = this.requestUserMap(userId ?? this.userManager.selfId);
        const oldValue = userMap.get("permission") ?? 0;
        this.requestUserMap(userId ?? this.userManager.selfId).set("permission", oldValue & (~flag));
    }
}
