import { _decorator, Asset, Component, Constructor, director, instantiate, Layers, Node, Prefab, SceneAsset, sp, Sprite, SpriteFrame, tween, utils, Vec3 } from 'cc';
import { Logger } from '../extend/Logger';
import { GameConst } from '../common/GameConst';
import { bundleMgr } from '../manager/BundleManager';
import Utils from './Utils';
import { uiMgr } from '../manager/UIManager';
import { PoolManager } from '../manager/PoolManager';
const { ccclass, property } = _decorator;

@ccclass('ResUtil')
export class ResUtil {
    /**
     * 根据名字加载一个新的模型与预制体或者缓存中的预制体
     * @param path 模型名字
     * @param cb 返回回调
     * @returns 返回参数
     */
    public static async loadModelPrefabName(path: string, cb?: (pfb: Node) => void): Promise<Node> {
        if (Utils.isNull(path)) {
            throw new Error("[ResUtil] 资源路径不能为空");
        }
        const pfb: Prefab = await bundleMgr.loadAsset(GameConst.bundleName.models, path, Prefab);
        let n: Node = instantiate(pfb);
        n.name = path;
        cb?.(n);
        return n;
    }

    /**
     * 设置精灵贴图 只能prefabs包 texture目录下
     * @param path 资源路径
     * 只能是在prefabs这个bundle目录下、然后如果使用
     * @param target 精灵或者节点
     * @param cb 回调函数
     */
    public static setSpriteFrame(name: string, target: Sprite | Node) {
        if(Utils.isNull(name))return;
        const path:string = `texture/${name}/spriteFrame`;
        bundleMgr.loadAsset(GameConst.bundleName.resources,path,SpriteFrame, (err: Error, clip: SpriteFrame) => {
            if(!err) {
                let sprite: Sprite = target instanceof Node ? target.getComponent(Sprite) : target;
                if (!sprite) {
                    console.error('Target node does not have a Sprite component!');
                }else{
                    sprite.spriteFrame = clip;
                }
            }
        });
    }

    /**
     * 设置精灵贴图 指定自定义的包
     * @param bundle 包名如果传空 默认prefabs包名
     * @param path 路径 如果在prefabs包下，就可以直接传递传图片名称或者path路径(hit_m or texture/hit_m/spriteFrame)
     * 如果不在prefabs包下就只能传递完成的路径(texture/hit_m/spriteFrame)
     * @param type 类型
     * @param target 图片或者节点
     * @param onComplete 设置完成的回调
     */
    public static setSpriteFrameAsset(
        bundle: string,
        path: string,
        type: Constructor<Asset>,
        target: Sprite | Node,
        onComplete?: (err: Error | null, asset?: any) => void){
        if(Utils.isNull(bundle)){
            bundle = GameConst.bundleName.resources;
            if(!path.startsWith("texture/")){
               path = `texture/${path}/spriteFrame`;
            }
        }
        if(Utils.isNull(path))return;
        bundleMgr.loadAsset(bundle,path,type, (err: Error, clip: SpriteFrame) => {
            if(!err) {
                let sprite: Sprite = target instanceof Node ? target.getComponent(Sprite) : target;
                if (!sprite) {
                    console.error('Target node does not have a Sprite component!');
                }else{
                    sprite.spriteFrame = clip;
                }
            }
            onComplete?.(err,clip);
        });
    }

    /**
     * 预加载场景资源（支持进度回调）
     * @param {string} sceneName - 场景名称（如 "main" 或者"level1"）
     * @param {Function} [onComplete] - 完成回调
     * @param {Function} [onProgress] - 加载进度回调
     * @param {Error | null} onProgress.err - 错误信息（成功时为 null）
     * @param {number} onProgress.progress - 加载进度（0~1）
     */
    public static preloadScene(
        sceneName: string,
        onComplete?: () => void,
        onProgress?: (err: Error | null, progress: number) => void
    ): void {
        if (Utils.isNull(sceneName)) {
            Logger.warn("[SceneLoader] Scene name cannot be null or empty!");
            return;
        }
        // 开始预加载场景
        director.preloadScene(
            sceneName,
            (loadedCount: number, totalCount: number) => {//进度更新回调
                const progress = totalCount > 0 ? loadedCount / totalCount : 0;
                onProgress?.(null, progress); // 通知进度（未完成）
            },//加载完成回调
            (error: Error | null, sceneAsset?: SceneAsset) => {
                if (error) {
                    Logger.error(`[SceneLoader] Failed to preload scene "${sceneName}":`, error);
                    onProgress?.(error,0); // 通知失败
                    return;
                }
                onComplete?.(); 
                //预加载成功
                Logger.log(`[SceneLoader] Scene "${sceneName}" preloaded successfully`);
                onProgress?.(null, 1); 
            }
        );
    }

    /**
     * 预加载场景成功后跳转 不黑屏这种
     * @param sceneName 场景名字
     */
    public static enteScene(sceneName: string){
        if(Utils.isNull(sceneName))return;
        this.preloadScene(sceneName,()=>{
            //启动场景
            uiMgr.showScene('main');
        });
    }

    /**
     * 播放spine动画
     * @param file "spine/effect_hecheng"
     * @param name "effect"
     * @param parent 
     * @param pos 
     * @param removetime 
     * @returns 
     */
    static async playSkAni(file: string, aniName: string, parent: Node, pos: Vec3, removetime: number = -1) {
        var node = new Node()
        node.parent = parent;
        node.position = pos;
        node.layer = Layers.BitMask.UI_2D;
        var skd = node.addComponent(sp.Skeleton);
        var data = await bundleMgr.loadAsset(GameConst.bundleName.resources,file,sp.SkeletonData) as sp.SkeletonData;
        skd.skeletonData = data;
        skd.setAnimation(0, aniName, false);
        if (removetime != -1) {
            tween(node).delay(removetime).call(() => {
                PoolManager.putNode(node);
            }).start();
        }
        return node;
    }
}

