import { Asset, AssetManager, assetManager, resources } from 'cc';
import { BundleProxy } from './BundleProxy';
import { ResProxy } from './ResProxy';

/**
 * 资源管理器
 * 职责:
 * - 统一管理Bundle和资源
 * - 提供BundleProxy和ResProxy的创建和管理
 * - 提供便捷的资源加载接口
 * - 管理资源缓存和释放
 */
export class ResMgr {
    private static _instance: ResMgr | null = null;
    
    /**
     * BundleProxy缓存
     * key: bundleName
     * value: BundleProxy
     */
    private _bundleProxies: Map<string, BundleProxy>;
    
    /**
     * ResProxy缓存
     * key: bundleName:path
     * value: ResProxy
     */
    private _resProxies: Map<string, ResProxy<any>>;
    
    /**
     * 构造函数(私有)
     */
    private constructor() {
        this._bundleProxies = new Map<string, BundleProxy>();
        this._resProxies = new Map<string, ResProxy<any>>();
        
        // 默认添加resources bundle
        this._bundleProxies.set('resources', new BundleProxy('resources', resources));
    }
    
    /**
     * 获取单例
     */
    static getInstance(): ResMgr {
        if (!this._instance) {
            this._instance = new ResMgr();
        }
        return this._instance;
    }
    
    /**
     * 生成缓存key
     */
    private getCacheKey(bundleName: string, path: string): string {
        return `${bundleName}:${path}`;
    }
    
    /**
     * 获取或创建BundleProxy
     * @param bundleName bundle名称
     * @returns BundleProxy
     */
    getBundleProxy(bundleName: string): BundleProxy {
        if (!this._bundleProxies.has(bundleName)) {
            // 尝试从assetManager获取已加载的bundle
            const bundle = assetManager.getBundle(bundleName);
            const bundleProxy = new BundleProxy(bundleName, bundle || undefined);
            this._bundleProxies.set(bundleName, bundleProxy);
        }
        return this._bundleProxies.get(bundleName)!;
    }
    
    /**
     * 加载Bundle
     * @param bundleName bundle名称
     * @returns Promise<BundleProxy>
     */
    async loadBundle(bundleName: string): Promise<BundleProxy> {
        const bundleProxy = this.getBundleProxy(bundleName);
        await bundleProxy.loadBundle();
        return bundleProxy;
    }
    
    /**
     * 获取或创建ResProxy
     * @param bundleName bundle名称
     * @param path 资源路径
     * @param type 资源类型
     * @returns ResProxy
     */
    getResProxy<T extends Asset>(
        bundleName: string,
        path: string,
        type: new (...args: any[]) => T
    ): ResProxy<T> {
        const cacheKey = this.getCacheKey(bundleName, path);
        
        if (!this._resProxies.has(cacheKey)) {
            const bundleProxy = this.getBundleProxy(bundleName);
            const resProxy = bundleProxy.createResProxy(path, type);
            this._resProxies.set(cacheKey, resProxy);
        }
        
        return this._resProxies.get(cacheKey)! as ResProxy<T>;
    }
    
    /**
     * 加载单个资源
     * @param bundleName bundle名称
     * @param path 资源路径
     * @param type 资源类型
     * @returns Promise<资源>
     */
    async load<T extends Asset>(
        bundleName: string,
        path: string,
        type: new (...args: any[]) => T
    ): Promise<T> {
        const resProxy = this.getResProxy(bundleName, path, type);
        return resProxy.load();
    }
    
    /**
     * 预加载资源
     * @param bundleName bundle名称
     * @param path 资源路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    async preload<T extends Asset>(
        bundleName: string,
        path: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<void> {
        const resProxy = this.getResProxy(bundleName, path, type);
        return resProxy.preload(onProgress);
    }
    
    /**
     * 加载目录
     * @param bundleName bundle名称
     * @param dir 目录路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<资源数组>
     */
    async loadDir<T extends Asset>(
        bundleName: string,
        dir: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<T[]> {
        const bundleProxy = this.getBundleProxy(bundleName);
        return bundleProxy.loadDir(dir, type, onProgress);
    }
    
    /**
     * 预加载目录
     * @param bundleName bundle名称
     * @param dir 目录路径
     * @param type 资源类型
     * @param onProgress 进度回调
     * @returns Promise<void>
     */
    async preloadDir<T extends Asset>(
        bundleName: string,
        dir: string,
        type: new (...args: any[]) => T,
        onProgress?: (finished: number, total: number) => void
    ): Promise<void> {
        const bundleProxy = this.getBundleProxy(bundleName);
        return bundleProxy.preloadDir(dir, type, onProgress);
    }
    
    /**
     * 释放资源
     * @param bundleName bundle名称
     * @param path 资源路径
     */
    release(bundleName: string, path: string): void {
        const cacheKey = this.getCacheKey(bundleName, path);
        
        // 从ResProxy缓存中获取并释放
        if (this._resProxies.has(cacheKey)) {
            const resProxy = this._resProxies.get(cacheKey)!;
            resProxy.release();
            // 可选:从缓存中移除ResProxy
            // this._resProxies.delete(cacheKey);
        } else {
            // 如果没有ResProxy,直接从BundleProxy释放
            const bundleProxy = this.getBundleProxy(bundleName);
            bundleProxy.release(path);
        }
    }
    
    /**
     * 释放目录资源
     * @param bundleName bundle名称
     * @param dir 目录路径
     */
    releaseDir(bundleName: string, dir: string): void {
        // 释放所有以dir开头的ResProxy
        const prefix = `${bundleName}:${dir}`;
        const keysToDelete: string[] = [];
        
        this._resProxies.forEach((resProxy, key) => {
            if (key.startsWith(prefix)) {
                resProxy.release();
                keysToDelete.push(key);
            }
        });
        
        // 可选:从缓存中移除ResProxy
        keysToDelete.forEach((key) => {
            // this._resProxies.delete(key);
        });
        
        // 从BundleProxy释放目录
        const bundleProxy = this.getBundleProxy(bundleName);
        bundleProxy.releaseDir(dir);
        
        console.log(`[ResMgr] 释放目录资源: ${bundleName}/${dir}, 共 ${keysToDelete.length} 个资源`);
    }
    
    /**
     * 释放Bundle的所有资源
     * @param bundleName bundle名称
     */
    releaseBundle(bundleName: string): void {
        // 释放该Bundle下所有的ResProxy
        const prefix = `${bundleName}:`;
        const keysToDelete: string[] = [];
        
        this._resProxies.forEach((resProxy, key) => {
            if (key.startsWith(prefix)) {
                resProxy.release();
                keysToDelete.push(key);
            }
        });
        
        // 从缓存中移除ResProxy
        keysToDelete.forEach((key) => {
            this._resProxies.delete(key);
        });
        
        // 释放BundleProxy的所有资源
        const bundleProxy = this.getBundleProxy(bundleName);
        bundleProxy.releaseAll();
        
        console.log(`[ResMgr] 释放Bundle所有资源: ${bundleName}, 共 ${keysToDelete.length} 个`);
    }
    
    /**
     * 释放所有资源
     */
    releaseAll(): void {
        console.log(`[ResMgr] 释放所有资源, 共 ${this._resProxies.size} 个ResProxy`);
        
        // 释放所有ResProxy
        this._resProxies.forEach((resProxy) => {
            resProxy.release();
        });
        this._resProxies.clear();
        
        // 释放所有BundleProxy的资源(除了resources)
        this._bundleProxies.forEach((bundleProxy, name) => {
            if (name !== 'resources') {
                bundleProxy.releaseAll();
            }
        });
    }
    
    /**
     * 获取缓存的ResProxy数量
     */
    getCacheSize(): number {
        return this._resProxies.size;
    }
    
    /**
     * 获取缓存的BundleProxy数量
     */
    getBundleCount(): number {
        return this._bundleProxies.size;
    }
    
    /**
     * 清空缓存(不释放资源)
     */
    clearCache(): void {
        console.log(`[ResMgr] 清空缓存, 共 ${this._resProxies.size} 个ResProxy`);
        
        // 清空所有ResProxy的缓存
        this._resProxies.forEach((resProxy) => {
            resProxy.clearCache();
        });
        this._resProxies.clear();
    }
    
    /**
     * 销毁Bundle
     * @param bundleName bundle名称
     */
    destroyBundle(bundleName: string): void {
        if (bundleName === 'resources') {
            console.warn('[ResMgr] 不能销毁resources bundle');
            return;
        }
        
        // 释放并移除该Bundle的所有ResProxy
        const prefix = `${bundleName}:`;
        const keysToDelete: string[] = [];
        
        this._resProxies.forEach((resProxy, key) => {
            if (key.startsWith(prefix)) {
                resProxy.release();
                keysToDelete.push(key);
            }
        });
        
        keysToDelete.forEach((key) => {
            this._resProxies.delete(key);
        });
        
        // 销毁BundleProxy
        if (this._bundleProxies.has(bundleName)) {
            const bundleProxy = this._bundleProxies.get(bundleName)!;
            bundleProxy.destroy();
            this._bundleProxies.delete(bundleName);
        }
        
        console.log(`[ResMgr] 销毁Bundle: ${bundleName}`);
    }
}
