
import { director, gfx, isValid, Scheduler, UIOpacity, UITransform, Vec2, Vec3 } from 'cc';
import { _decorator, Prefab, log, instantiate,Node, assetManager, v2, view,tween } from 'cc';
import { Util } from '../../module/util';
import { PrefabBase } from '../base/prefabBase';
import { Msgbox } from '../winsrc/msgbox';

const { ccclass, property } = _decorator;


export default class PrefabManager {
    private pBundle:any|null=null;                 // 已加载的资源包

    private pWinNode: Node|null=null;                         // 窗体父节点
    private prfbList:{[index:string]: Prefab} = {} // 已加载的prefab
    private pPrevPrefab:Node|null = null; // 正在展示的prefab节点
    private pNowShowName:string = '';  // 正在展示的prefab节点名称
    private pIsShow:boolean = false; // 是否正在切换显示

    private pDialogNode: Node|null=null;                         // 窗体父节点
    private prfbDialogList:{[index:string]: Prefab} = {} // 已加载的prefab
    private pIsShowDialog:boolean = false; // 是否正在切换显示

    private pMenu:Node|null=null; // 菜单父节点
    private pMenuList:{[index:string]: Prefab} = {} // 已加载的Menu
    private pNowShowMenu:string = '';  // 正在展示的菜单名称
    private pPrevMenu:Node|null = null; // 正在展示的菜单节点
    private pIsShowMenu:boolean = false; // 是否正在切换显示

    private pMsgNode:Node|null=null; // 消息提示框父节点
    private pMsgList:{[index:string]: Prefab} = {} // 已加载的消息框
    private pIsShowMsg:boolean = false; // 是否正在切换显示

    public constructor() {
        this.pWinNode = this.addSceneNode('prefabManagerWinNode');
        this.pMenu = this.addSceneNode('prefabManagerMenuNode');
        this.pMsgNode = this.addSceneNode('prefabManagerMsgNode');
        this.pDialogNode = this.addSceneNode('prefabManagerDialogNode')
    }
    // 对当前场景添加一个节点
    private addSceneNode(prefabManagerName:string){
        Util.log('scene名字====' + director.getScene()?.name);
        let scene = director.getScene()?.getChildByName('Canvas');
        if(scene){
            Util.log('添加了一个显示节点..' + prefabManagerName);
            let node = scene.getChildByName(prefabManagerName)?.getComponent(UITransform)?.node;
            if(!node){
                node = new Node(prefabManagerName);
                scene.addChild(node);
                node.addComponent(UITransform);
            }
            return node;
        }
        else{
            Util.log('没有找到场景....');
            return null;
        }
        
    }
    private checkParentNode(){
        if(!this.pWinNode || (this.pWinNode && !this.pWinNode.isValid)){
            this.pWinNode = this.addSceneNode('prefabManagerWinNode');
        }
        if(!this.pMenu || (this.pMenu && !this.pMenu.isValid)){
            this.pMenu = this.addSceneNode('prefabManagerMenuNode');
        }
        if(!this.pMsgNode || (this.pMsgNode && !this.pMsgNode.isValid)){
            this.pMsgNode = this.addSceneNode('prefabManagerMsgNode');
        }
        if(!this.pDialogNode || (this.pDialogNode && !this.pDialogNode.isValid)){
            this.pDialogNode = this.addSceneNode('prefabManagerDialogNode');
        }
    }

    // 显示一个预制体窗体
    public showPrefab(name:string, params:object|null=null){
        if( (this.pNowShowName == name && isValid(this.pPrevPrefab,true) ) || this.pIsShow)
            return;
        this.pIsShow = true;
        Util.log('开始切换窗体!name=' + name);
        let pre = this.prfbList[name];
        if(!pre){
            this.loadPrefab(name, this.showWin.bind(this), 1, params);
        }
        else{
            this.showWin(pre,name, params);
        }
    }
    // 显示一个预制体窗体Dialog
    public showDialogPrefab(name:string, params:object|null=null){
        if(this.pIsShowDialog)
            return;
        this.pIsShowDialog = true;
        Util.log('开始展示Dialog窗体!name=' + name);
        let pre = this.prfbDialogList[name];
        if(!pre){
            this.loadPrefab(name, this.showDialog.bind(this), 4, params);
        }
        else{
            this.showDialog(pre,name, params);
        }
    }
    // 加载资源包
    public loadBundle(name:string){
        let pThis = this;
        if(null == this.pBundle){
            assetManager.loadBundle(name, function (err:any, bundle:any) {
                if(!bundle){
                    Util.log('bundle获取失败!');
                    return;
                }
                Util.log('加载bundle完成...');
                pThis.pBundle = bundle;
            });
        }
    }
    // 加载一个prefab
    private loadPrefab(name:string,callBack:any, type:number, parms:object|null=null){
        let pThis = this;
        Util.log('加载窗体...name='+ name);
        if(null == this.pBundle){
            assetManager.loadBundle("win", function (err:any, bundle:any) {
                if(!bundle){
                    Util.log('bundle获取失败!');
                    pThis.pIsShow = false;
                    return;
                }
                Util.log('加载bundle完成...');
                pThis.pBundle = bundle;
                pThis.loadPrefab(name, callBack, type, parms);
            });
            return;
        }
        this.pBundle.load(name,Prefab, function (err:any, prefab:any) {
            if (!prefab) {
                Util.log("预制体为空" + err);
                pThis.pIsShow = false;
                return;
            }
            Util.log('加载Prefab成功!');
            if(type == 1){
                pThis.prfbList[name] = prefab;
            }
            else if(type == 2){
                pThis.pMsgList[name] = prefab;
            }
            else if(type == 3){
                pThis.pMenuList[name] = prefab;
            }
            else if(type == 4){
                pThis.prfbDialogList[name] = prefab;
            }
            if(callBack){
                callBack(prefab, name,parms);
            }
        });
    }
    // 显示基础窗体
    private showWin(prefab:Prefab, name:string, params:object|null){
        let newNode = instantiate(prefab);
        if (!newNode) {
            Util.log("节点为空");
            this.pIsShow = false;
            return;
        }
        Util.log('添加节点中...');
        // 此处先检查一下节点有效性
        this.checkParentNode();
        if(!this.pWinNode){
            Util.log('空节点,不可展示!');
            newNode.destroy();
            return;
        }
        // 添加为当前节点的子节点
        this.pWinNode.addChild(newNode);
        
        let prevNode = this.pPrevPrefab;
        let pNode = this.pWinNode;
        let pThis = this;
        // 执行子节点展示动画
        if(prevNode != null){
            newNode.setPosition(view.getVisibleSize().x, 0);
            Util.log("开始动画 " + name);
            tween(newNode) .to(0.1, {position: new Vec3(0, 0, 0)}).delay(0.1) .call(() => { 
                if(null != prevNode && isValid(prevNode, true)){
                    prevNode.destroy(); // 销毁节点
                }
                pThis.pIsShow = false;
                Util.log("执行完毕 " + name);
             }) .start();
        }
        else{
            pThis.pIsShow = false;
            Util.log("执行完毕,第一个窗体");
        }
        
         // 传递参数
         let nBase = newNode.getComponent(PrefabBase);
         if(nBase && params){
             nBase.init(params);
         }
         this.pPrevPrefab = newNode;
         this.pNowShowName = name;
    }
    // 显示Dialog窗体
    private showDialog(prefab:Prefab, name:string, params:object|null){
        let newNode = instantiate(prefab);
        if (!newNode) {
            Util.log("节点为空");
            this.pIsShowDialog = false;
            return;
        }
        Util.log('添加节点中...');
        // 此处先检查一下节点有效性
        this.checkParentNode();
        if(!this.pDialogNode){
            Util.log('空节点,不可展示!');
            return;
        }
        // 添加为当前节点的子节点
        this.pDialogNode.addChild(newNode);

        let pThis = this;
        // 执行子节点展示动画
        newNode.setPosition(view.getVisibleSize().x/2, 0);
        let op = newNode.getComponent(UIOpacity);
        if(op){
            op.opacity = 0;
            Util.log("开始动画");
            tween(op).to(0.2, {opacity:255}).start();
        }
        tween(newNode).to(0.2, {position: new Vec3(0, 0, 0)}).delay(0.1).call(() => { 
            pThis.pIsShowDialog = false;
            Util.log("执行完毕");
        }).start();
        
         // 传递参数
         let nBase = newNode.getComponent(PrefabBase);
         if(nBase && params){
             nBase.init(params);
         }
    }
    // 显示一个菜单
    public showMenu(name:string){
        if( (this.pNowShowMenu == name && isValid(this.pPrevMenu,true) ) || this.pIsShowMenu)
            return;
        this.pIsShowMenu = true;
        Util.log('开始切换菜单!name=' + name);
        let pre = this.pMenuList[name];
        if(!pre){
            this.loadPrefab(name, this.showMenus.bind(this), 3);
        }
        else{
            this.showMenus(pre,name);
        }
    }
    // 展示菜单
    private showMenus(prefab:Prefab, name:string){
        let newNode = instantiate(prefab);
        if (!newNode) {
            Util.log("菜单节点为空");
            this.pIsShowMenu = false;
            return;
        }
        Util.log('添加菜单中...');
        // 此处先检查一下节点有效性
        this.checkParentNode();
        if(!this.pMenu){
            Util.log('空节点,不可展示!');
            return;
        }
        
        let prevNode = this.pPrevMenu;
        let pNode = this.pMenu;
        let pThis = this;

        // 执行子节点展示动画
        let height = pNode.getComponent(UITransform)?.height;
        height = height ? height : 100;
        let oldY = -( (view.getVisibleSize().height / 2) - (height/2) );
        pNode.setPosition(new Vec3(0, oldY, 0));
        
        pNode.getComponent(UITransform)?.scheduleOnce(function() {
            // 添加为当前节点的子节点
            pNode.addChild(newNode);
            if(null != prevNode && isValid(prevNode, true)){
                prevNode.destroy();
            }
            pThis.pIsShowMenu = false;
            Util.log("执行完毕");
        },0);
         this.pPrevMenu = newNode;
         this.pNowShowMenu = name;
    }
    // 显示提示框
    public msg(txt:string,time:number=0){
        this.showMsg('Msg', txt, time);
    }
    // 显示弹框
    public msgBox(title:string, txt:string, isShowCannel:boolean, callback:Function|null, callback2:Function|null){
        this.showMsg('Msg', txt, 0, title, 2, isShowCannel, callback, callback2);
    }
    // 显示一个提示框
    // time:展示时间,秒,
    // txt: 展示内容
    // title:弹窗标题
    // type:弹窗类型,1:只有内容的提示框, 2:有确定按钮的提示框, 3:有确定和取消的选择提示框
    // callback:弹窗关闭时回调函数
    private showMsg(name:string,txt:string,time:number=0,title:string='',type:number=1,isShowCannel:boolean=false,callback:Function|null=null,callback2:Function|null=null){
        if(this.pIsShowMsg)
            return;
        this.pIsShowMsg = true;
        Util.log('开始显示msg!name=' + name);
        let pre = this.pMsgList[name];
        let parms = {'time':time,'txt':txt,'title':title,'type':type,'callback':callback,'callback2':callback2,'isShowCannel':isShowCannel};
        if(!pre){
            this.loadPrefab(name, this.showMsgs.bind(this), 2, parms);
        }
        else{
            this.showMsgs(pre,name,parms);
        }
    }
    // 展示菜单
    private showMsgs(prefab:Prefab, name:string, parms:object|null){
        let newNode = instantiate(prefab);
        if (!newNode) {
            Util.log("菜单节点为空");
        }
        else{
            Util.log('准备展示msg中...');
            // 此处先检查一下节点有效性
            this.checkParentNode();
            if(!this.pMsgNode){
                Util.log('空节点,不可展示!');
                return;
            }
            let m = newNode.getComponent(Msgbox);
            if(m){
                // 添加为当前节点的子节点
                this.pMsgNode.addChild(newNode);
                m.showMsg(parms);
            }
            else{
                Util.log('展示msg失败...');
                newNode.destroy();
            }
        }
        this.pIsShowMsg = false;
    }
}
declare global {
    interface Window {
        PrefabManager: any
    }
  }
window.PrefabManager = new PrefabManager();
