import { _decorator, assetManager, Component, director,instantiate,Node, Prefab, Vec3} from 'cc';
import { Singleton } from './Singleton';
import { bundleMgr } from './BundleManager';
import { GameConst } from '../common/GameConst';
import Utils from '../utils/Utils';
import { Logger } from '../extend/Logger';

const { ccclass, property } = _decorator;

interface PageActive{
    show: () => {},
    hide: () => {},
    back: () => {},
}

@ccclass("UIManager")
export class UIManager extends Singleton {
    //tabbar pages主页面节点放在这个容器中
    private pageUIs: string = 'pageUIs';
    //pop dialog出来的节点放在这个容器中
    private popUIs: string = 'popUIs';
    //页面缓存
    public panels = new Map <string, Node>();

    /**
    * 展示场景
    * @param sceneName 场景名字
    * @param delay 延迟的时间
    */
    public showScene(sceneName: string, delay: number = 0.1): void {
        if (delay) {
            setTimeout(() => {
                director.loadScene(sceneName);
            }, delay * 1000);
        } else {
            director.loadScene(sceneName);
        }
    }

    /**
     * 展示一个resources资源包里的节点
     * @param path Prefab的路径名称
     * @param args 给组建传递的参数
     * @param cb 展示完成的回调函数
     * @returns 
     */
    public async show(path: string, args?: any, cb?: Function): Promise<Node>{
        let prefabNames = path.split('/').pop();
        if (!args) {args = [];}
        const scriptName = prefabNames.replace(/^\w/, (c) => c.toUpperCase());
        let panel: Node = await this.asyncLoad(path);
        if(!panel)return;
        //动态添加页面的路径path信息，在关闭和销毁的时候用到
        panel['_uiPath'] = path;
        let isMain = Object.values(GameConst.mainUIs).includes(path);
        const name: string = isMain ? this.pageUIs : this.popUIs;
        const parent:Node = Utils.findName(this.getCurentSceneRoot(),name);
        panel.parent = parent;
        if(isMain){
            parent.children.forEach((e:Node) => {
                e.setPosition(new Vec3(e.name == scriptName ? 0 : 50000,0));
            });
        }else{
            panel.setSiblingIndex(parent.children.length);
        }
        const comp = panel.getComponent(scriptName);
        if (comp && (comp as Component & PageActive)['show']){
            (comp as Component & PageActive)['show'].apply(comp, args);
        }
        if(typeof cb === 'function') {cb?.(panel)};
    }

    /**
     * 根据堆栈页面顺序返回到某一个页面
     * @param path 返回某一个界面
     * @param args 返回的附带参数
     * @param cb 回调
     * @returns 
     */
    public pop(path?: string,args?: any,cb?: Function){
        let canvas:Node = this.getCurentSceneRoot();
        let popUIs:Node = Utils.findName(canvas,this.popUIs);
        let isMain:boolean = Object.values(GameConst.mainUIs).includes(path);
        let comp:any = null;
        if(Utils.isNull(path)){
            if(popUIs.children.length > 0){//关闭存在的popUIs最后一个节点
               let node: Node = popUIs.children.slice(-2)[0];
               node.parent = null;
               comp = node.getComponent(node.name);
            }else{//返回主页面的上一层节点
               comp = this.getPageComponent(GameConst.mainUIs.page1);
               comp.tabBarIndex = comp.preIndexs.slice(-2)[0];
            }
        }else{
            let scriptName = path.split('/').pop().replace(/^\w/, (c) => c.toUpperCase());
            if (!args) {args = [];}
            if(isMain){
                comp = this.getPageComponent(GameConst.mainUIs.page1);
                comp.tabBarIndex = comp.sceneNames.indexOf(path);
                popUIs.removeAllChildren();
            }else{
                let panel: Node = this.panels.get(path);
                let targetIndex = popUIs.children.findIndex(n => n.name === scriptName);
                if (targetIndex !== -1) {
                    popUIs.children.slice(targetIndex + 1).forEach(n => {
                        n.parent = null;
                    });
                    popUIs.children.splice(targetIndex + 1);
                }
                panel.setSiblingIndex(panel.parent.children.length);
                comp = panel.getComponent(scriptName);
            }
        }
        if(comp && (comp as Component & PageActive)['pop']){
           (comp as Component & PageActive)['pop'].apply(comp, args);
        }
        if(typeof cb === 'function') {cb?.()};
    }

    /**
     * 直接关闭固定的名字中的一个页面
     * @param path Prefab的路径名称
     * @param cb 展示完成的回调函数
     * @returns 
     */
    public hide(path: string,cb?: Function){
        if(!this.panels.has(path))return;
        let panel: Node = this.panels.get(path);
        const scriptName = path.split('/').pop().replace(/^\w/, (c) => c.toUpperCase());
        let isMain = Object.values(GameConst.mainUIs).includes(path);
        if(isMain){
            let container = Utils.findName(this.getCurentSceneRoot(),this.pageUIs);
            container.children.forEach((e:Node) => {
                e.setPosition(new Vec3(e.name == scriptName ? 5000 : 0,0));
            });
        }else{
            panel.parent = null;
            const comp = panel.getComponent(scriptName);
            if (comp && (comp as Component & PageActive)['hide']){
                (comp as Component & PageActive)['hide'].apply(comp);
            }
            if(typeof cb === 'function') {cb?.()};
        }
    }

    /**
     * 得到一个prefabs预制体页面
     * @param path 主要路径节点
     * @returns 返回一个节点
     */
    public async asyncLoad(path: string): Promise<Node>{
        return new Promise((resolve, reject) => {
            if(this.panels.has(path)){
                let page: Node = this.panels.get(path)!;
                return resolve && resolve(page);
            }else{
                bundleMgr.loadAsset(GameConst.bundleName.resources,path,Prefab,(err, prefab)=>{
                    if (err) {
                        Logger.error("加载动画资源失败：", err);
                        reject && reject();
                    }else{
                        let page: Node = instantiate(prefab!);
                        this.panels.set(path, page);
                        return resolve && resolve(page);
                    }
                });
            }
        });
    }

    /**
     * 从缓存页面中获取一个脚本
     * @param path 缓存的路径
     * @param scriptName 不传默认获取path名字最后一个字符串作为脚本的名字
     * @returns 
     */
    public getPageComponent(path: string,scriptName?:string): any{
        if(!this.panels.has(path)){
           return null;
        }else{
            let name:string = scriptName ? scriptName : path.split('/').pop();
            let node: Node = this.panels.get(path);
            return node.getComponent(name);
        }
    }

    /**
     *从缓存页面中获取一个页面
     * @param path 缓存的路径
     */
     public getPageNode(path: string): Node{
        if(Utils.isNull(path))return null;
        if(!this.panels.has(path))return null;
        return this.panels.get(path);
    }

    /**
     * 在界面中显示的节点是否存在
     */
    public hasPageNode(path: string): boolean{
        if(Utils.isNull(path))return false;
        let name = path.split('/').pop();
        let canvas:Node = this.getCurentSceneRoot();
        let pages = Utils.findName(canvas,this.pageUIs);
        let popUIs = Utils.findName(canvas,this.popUIs);
        let nodes = pages.children.concat(popUIs.children)
        return nodes.some(e=>e.name == name);
    }

    /**
     * 得到当前场景的节点的根节点
     * @returns 根结点
     */
    public getCurentSceneRoot(): Node {
        return director.getScene().getChildByName('Canvas');
    }
}

//全局单例
export const uiMgr = UIManager.ins();
