import { IUIItem } from './UIDef';

const { ccclass, property } = cc._decorator;


enum UILoadingState {
    none,
    loading,
    show,
    close,
};   
class UILoadingHandle {
    private static _idBase = 0;
    private _instId: number = 0;
    constructor(){
        this._instId = UILoadingHandle._idBase++;
    }

    public get instId(): number {
        return this._instId;
    }

    state: UILoadingState = UILoadingState.loading;
    asset: cc.Asset;
    node: cc.Node;
    uiData: IUIItem;

    destory(){
        if(cc.isValid(this.node, true)) {
            this.node.destroy();
        }
        this.asset && this.asset.decRef();
        this.state = UILoadingState.close;
    }
}

/**
 * @en the `User Interface Manager`, handles some stuffs like the ui loads,ui layers,resizing etc.
 * @zh UI管理器，处理UI加载，层级，窗口变化等
 * 
 * */
export class UIMgr {

    private static _inst: UIMgr;
    public static get inst(): UIMgr {
        if (this._inst == null) {
            this._inst = new UIMgr();
        }
        return this._inst;
    }

    private _uiCanvas: cc.Node;
    private _uiRoot: cc.Node;
    handleArr:UILoadingHandle[] = [];  // 允许打开两个相同的界面

    private createFullScreenNode() {
        let canvas = this._uiCanvas;
        let node = new cc.Node();
        node.group = this._uiCanvas.group;
        node.width = canvas.width;
        node.height = canvas.height;

        let widget = node.addComponent(cc.Widget);
        widget.isAlignBottom = true;
        widget.isAlignTop = true;
        widget.isAlignLeft = true;
        widget.isAlignRight = true;

        widget.left = 0;
        widget.right = 0;
        widget.top = 0;
        widget.bottom = 0;
        return node;
    }

    /**
     * @en setup this UIMgr,`don't call more than once`.
     * @zh 初始化UIMgr,`不要多次调用`
     *  */
    public setup(uiCanvas: cc.Node | cc.Prefab, maxLayers: number, layerNames?: Array<string>) {
        if (this._uiCanvas) {
            return;
        }

        if (!uiCanvas) {
            cc.error('uiCanvas must be a cc.Node or cc.Prefab');
            return;
        }
        if (uiCanvas instanceof cc.Node) {
            this._uiCanvas = uiCanvas;
        }
        else {
            this._uiCanvas = cc.instantiate(uiCanvas);
            cc.director.getScene().addChild(this._uiCanvas);
        }

        this._uiCanvas.name = '$tgxUICanvas$';


        layerNames ||= [];

        this._uiRoot = this.createFullScreenNode();
        this._uiRoot.name = 'ui_root'
        this._uiCanvas.addChild(this._uiRoot);

        //create layers
        for (let i = 0; i < maxLayers; ++i) {
            let layerNode = this.createFullScreenNode();
            layerNode.name = 'ui_layer_' + (layerNames[i] ? layerNames[i] : i);
            this._uiRoot.addChild(layerNode);
            layerNode.on(cc.Node.EventType.CHILD_REMOVED, this.uiRemove, this);
        }
    }

    private uiRemove(node: cc.Node){
        let index = this.handleArr.findIndex((v)=>{
            return v.node.uuid == node.uuid;
        });

        if(index != -1) {
            this.hideUIIndex(index);
        }
    }

    public getLayerNode(layerIndex: number): cc.Node {
        return this._uiRoot.children[layerIndex] || this._uiRoot;
    }

    public getUI(uiData: IUIItem): UILoadingHandle {
        return this.handleArr.find((v)=>{return v.uiData.prefab == uiData.prefab});
    }

    public isShowing(uiData: IUIItem): boolean {
        let find = this.getUI(uiData);
        if(!find) return false;

        return find.state == UILoadingState.loading || find.state == UILoadingState.show;
    }

    public showUI(uiData: IUIItem) {

        let handle = new UILoadingHandle();
        handle.state = UILoadingState.loading;
        handle.uiData = uiData;
        this.handleArr.push(handle);

        cc.resources.load(uiData.prefab, cc.Prefab, (err, res)=>{
            if(err){
                console.log(err);
                this.showUI(uiData);
                return;
            }

            if(handle.state == UILoadingState.loading){
                let node = cc.instantiate(res);
                let layer = this.getLayerNode(uiData.layer);
                layer.addChild(node);
    
                handle.state = UILoadingState.show;
                handle.asset = res;
                handle.node = node;
                res.addRef();
            }
            else{
                cc.assetManager.releaseAsset(res);
            }

        })

        return handle;
    }

    //注：同一个prefab可能会有多个实例，只有一个实例时调用。
    public hideUI(uiData: IUIItem){
        let index = this.handleArr.findIndex((v)=>{return v.uiData.prefab == uiData.prefab});;
        if(index==-1) return;

        this.hideUIIndex(index);
    }

    
    public hideUIIndex(index: number){
        let find = this.handleArr[index];
        find.destory();
        this.handleArr.splice(index, 1);
    }
}

window['uiMgr'] = function(){ 
    return UIMgr.inst;
}