import { Asset, AssetManager, assetManager } from 'cc';
import { ResProxy } from './ResProxy';
/**
 * Bundle代理类
 * 职责:
 * - 异步加载Bundle
 * - 管理Bundle的生命周期
 * - 提供从Bundle加载资源的统一接口
 */
export class BundleProxy {
    private _bundleName: string;
    private _bundle: AssetManager.Bundle | null = null;
    private _loading: Promise<AssetManager.Bundle> | null = null;

    constructor(bundleName: string, bundle?: AssetManager.Bundle) {
        this._bundleName = bundleName;
        this._bundle = bundle || null;
    }

    /**
     * 获取Bundle名称
     */
    get bundleName(): string {
        return this._bundleName;
    }

    /**
     * 获取Bundle实例(同步)
     */
    get bundle(): AssetManager.Bundle | null {
        return this._bundle;
    }

    /**
     * 异步加载Bundle
     * @returns Promise<AssetManager.Bundle>
     */
    async loadBundle(): Promise<AssetManager.Bundle> {
        // 如果已经加载完成,直接返回
        if (this._bundle) {
            return this._bundle;
        }

        // 如果正在加载中,返回加载Promise
        if (this._loading) {
            return this._loading;
        }

        // 开始加载
        this._loading = new Promise<AssetManager.Bundle>((resolve, reject) => {
            console.log(`[BundleProxy] 开始加载Bundle: ${this._bundleName}`);
            
            assetManager.loadBundle(this._bundleName, (err, bundle) => {
                if (err) {
                    console.error(`[BundleProxy] 加载Bundle失败: ${this._bundleName}`, err);
                    this._loading = null;
                    reject(err);
                    return;
                }

                this._bundle = bundle;
                this._loading = null;
                console.log(`[BundleProxy] Bundle加载成功: ${this._bundleName}`);
                resolve(bundle);
            });
        });

        return this._loading;
    }

    /**
     * 创建资源代理
     * @param path 资源路径
     * @param type 资源类型
     * @returns ResProxy
     */
    createResProxy<T extends Asset>(
        path: string,
        type: new (...args: any[]) => T
    ): ResProxy<T> {
        return new ResProxy<T>(this, path, type);
    }

    /**
     * 加载资源
     * @param path 资源路径
     * @param type 资源类型
     * @returns Promise<资源>
     */
    async loadRes<T extends Asset>(
        path: string,
        type: new (...args: any[]) => T
    ): Promise<T> {
        const bundle = await this.loadBundle();
        
        return new Promise((resolve, reject) => {
            console.log(`[BundleProxy] 开始加载资源: ${this._bundleName}/${path}`);
            
            bundle.load(path, type, (err, asset) => {
                if (err) {
                    console.error(`[BundleProxy] 加载资源失败: ${this._bundleName}/${path}`, err);
                    reject(err);
                    return;
                }

                console.log(`[BundleProxy] 资源加载成功: ${this._bundleName}/${path}`);
                resolve(asset as T);
            });
        });
    }

    /**
     * 预加载资源
     * @param path 资源路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    async preload<T extends Asset>(
        path: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<void> {
        const bundle = await this.loadBundle();

        return new Promise((resolve, reject) => {
            console.log(`[BundleProxy] 开始预加载资源: ${this._bundleName}/${path}`);

            bundle.preload(
                path,
                type,
                (finished, total) => {
                    if (onProgress) {
                        onProgress(finished, total);
                    }
                },
                (err) => {
                    if (err) {
                        console.error(`[BundleProxy] 预加载资源失败: ${this._bundleName}/${path}`, err);
                        reject(err);
                        return;
                    }

                    console.log(`[BundleProxy] 资源预加载成功: ${this._bundleName}/${path}`);
                    resolve();
                }
            );
        });
    }

    /**
     * 加载目录
     * @param dir 目录路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<资源数组>
     */
    async loadDir<T extends Asset>(
        dir: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<T[]> {
        const bundle = await this.loadBundle();

        return new Promise((resolve, reject) => {
            console.log(`[BundleProxy] 开始加载目录: ${this._bundleName}/${dir}`);

            bundle.loadDir(
                dir,
                type,
                (finished, total) => {
                    if (onProgress) {
                        onProgress(finished, total);
                    }
                },
                (err, assets) => {
                    if (err) {
                        console.error(`[BundleProxy] 加载目录失败: ${this._bundleName}/${dir}`, err);
                        reject(err);
                        return;
                    }

                    console.log(`[BundleProxy] 目录加载成功: ${this._bundleName}/${dir}, 共 ${assets.length} 个资源`);
                    resolve(assets as T[]);
                }
            );
        });
    }

    /**
     * 预加载目录
     * @param dir 目录路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    async preloadDir<T extends Asset>(
        dir: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<void> {
        const bundle = await this.loadBundle();

        return new Promise((resolve, reject) => {
            console.log(`[BundleProxy] 开始预加载目录: ${this._bundleName}/${dir}`);

            bundle.preloadDir(
                dir,
                type,
                (finished, total) => {
                    if (onProgress) {
                        onProgress(finished, total);
                    }
                },
                (err) => {
                    if (err) {
                        console.error(`[BundleProxy] 预加载目录失败: ${this._bundleName}/${dir}`, err);
                        reject(err);
                        return;
                    }

                    console.log(`[BundleProxy] 目录预加载成功: ${this._bundleName}/${dir}`);
                    resolve();
                }
            );
        });
    }

    /**
     * 释放资源
     * @param path 资源路径
     */
    release(path: string): void {
        if (!this._bundle) {
            console.warn(`[BundleProxy] Bundle未加载,无法释放资源: ${this._bundleName}/${path}`);
            return;
        }

        this._bundle.release(path);
        console.log(`[BundleProxy] 释放资源: ${this._bundleName}/${path}`);
    }

    /**
     * 释放目录资源
     * @param dir 目录路径
     */
    releaseDir(dir: string): void {
        if (!this._bundle) {
            console.warn(`[BundleProxy] Bundle未加载,无法释放目录: ${this._bundleName}/${dir}`);
            return;
        }

        // Cocos没有直接的releaseDir方法,需要手动释放目录下的资源
        // 这里简化处理,实际使用时可能需要追踪加载的资源
        console.log(`[BundleProxy] 释放目录资源: ${this._bundleName}/${dir}`);
    }

    /**
     * 释放所有资源
     */
    releaseAll(): void {
        if (!this._bundle) {
            console.warn(`[BundleProxy] Bundle未加载,无法释放所有资源: ${this._bundleName}`);
            return;
        }

        this._bundle.releaseAll();
        console.log(`[BundleProxy] 释放所有资源: ${this._bundleName}`);
    }

    /**
     * 销毁Bundle
     */
    destroy(): void {
        if (this._bundle) {
            this.releaseAll();
            this._bundle = null;
        }
        this._loading = null;
    }
}
