import { SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc';
import { HttpUtil } from './HttpUtil';
import { ApiLevelData, ApiResponse, RuntimeLevelConfig } from '../types/LevelTypes';
import { API_ENDPOINTS, API_TIMEOUT } from '../config/ApiConfig';

/**
 * 进度回调类型
 * @param progress 进度值 0-1
 * @param message 进度消息
 */
export type ProgressCallback = (progress: number, message: string) => void;

/**
 * 关卡数据管理器
 * 单例模式，负责从 API 获取关卡数据并按需加载图片
 */
export class LevelDataManager {
    private static _instance: LevelDataManager | null = null;

    /** API 请求重试次数 */
    private readonly API_RETRY_COUNT = 2;

    /** API 返回的原始关卡数据 */
    private _apiData: ApiLevelData[] = [];

    /** 运行时关卡配置缓存（按需填充） */
    private _levelConfigs: Map<number, RuntimeLevelConfig> = new Map();

    /** 是否已成功从 API 获取数据 */
    private _hasApiData: boolean = false;

    /** 图片缓存：URL -> SpriteFrame */
    private _imageCache: Map<string, SpriteFrame> = new Map();

    /** 正在加载中的关卡索引集合 */
    private _loadingLevels: Set<number> = new Set();

    /**
     * 获取单例实例
     */
    static get instance(): LevelDataManager {
        if (!this._instance) {
            this._instance = new LevelDataManager();
        }
        return this._instance;
    }

    /**
     * 私有构造函数
     */
    private constructor() {}

    /**
     * 初始化：从 API 获取数据并预加载第一关图片
     * @param onProgress 进度回调
     * @returns 是否初始化成功
     */
    async initialize(onProgress?: ProgressCallback): Promise<boolean> {
        console.log('[LevelDataManager] 开始初始化');

        try {
            // 阶段1: 获取 API 数据 (0-30%)
            onProgress?.(0, '正在请求服务端数据...');
            const apiData = await this._fetchApiData(onProgress);

            if (!apiData || apiData.length === 0) {
                console.warn('[LevelDataManager] API 返回空数据');
                onProgress?.(0.3, '网络异常，请重新打开游戏');
                return false;
            }

            console.log(`[LevelDataManager] 获取到 ${apiData.length} 个关卡数据`);
            this._apiData = apiData;
            this._hasApiData = true;
            onProgress?.(0.3, `获取到 ${apiData.length} 个关卡`);

            // 阶段2: 只预加载第一关图片 (30-80%)
            const firstLevel = apiData[0];
            onProgress?.(0.3, '正在加载游戏必备资源...');

            const [spriteFrame1, spriteFrame2] = await Promise.all([
                this._loadImage(firstLevel.image1Url),
                this._loadImage(firstLevel.image2Url),
            ]);
            this._levelConfigs.set(0, this._createRuntimeConfig(firstLevel, spriteFrame1, spriteFrame2));

            console.log('[LevelDataManager] 初始化完成，第一关资源已加载');
            onProgress?.(0.8, '游戏资源加载完成');

            return true;
        } catch (error) {
            console.error('[LevelDataManager] 初始化失败:', error);
            onProgress?.(0.3, '网络异常，请重新打开游戏');
            return false;
        }
    }

    /**
     * 获取指定关卡配置
     * @param index 关卡索引
     */
    getLevelConfig(index: number): RuntimeLevelConfig | null {
        return this._levelConfigs.get(index) ?? null;
    }

    /**
     * 获取关卡总数
     */
    getLevelCount(): number {
        return this._apiData.length;
    }

    /**
     * 获取指定索引的关卡 ID
     * @param index 关卡索引
     */
    getLevelId(index: number): string | null {
        if (index < 0 || index >= this._apiData.length) {
            return null;
        }
        return this._apiData[index].id;
    }

    /**
     * 检查指定索引的关卡是否已通关
     * @param index 关卡索引
     */
    isLevelCompleted(index: number): boolean {
        if (index < 0 || index >= this._apiData.length) {
            return false;
        }
        return this._apiData[index].completed;
    }

    /**
     * 获取第一个未通关的关卡索引
     * 遍历关卡列表，返回第一个 completed === false 的索引
     * 如果全部通关，返回最后一关的索引
     * @returns 第一个未通关关卡索引（0-based）
     */
    getFirstUncompletedIndex(): number {
        for (let i = 0; i < this._apiData.length; i++) {
            if (!this._apiData[i].completed) {
                return i;
            }
        }
        // 全部通关，返回最后一关
        return Math.max(0, this._apiData.length - 1);
    }

    /**
     * 获取指定索引之后第一个未通关的关卡索引
     * @param afterIndex 从该索引之后开始查找（不含该索引）
     * @returns 下一个未通关关卡索引，如果后续全部通关则返回 -1
     */
    getNextUncompletedIndex(afterIndex: number): number {
        for (let i = afterIndex + 1; i < this._apiData.length; i++) {
            if (!this._apiData[i].completed) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 标记指定关卡为已通关（本地缓存更新）
     * @param index 关卡索引
     */
    markLevelCompleted(index: number): void {
        if (index < 0 || index >= this._apiData.length) {
            return;
        }
        this._apiData[index].completed = true;

        // 同时更新运行时配置的 completed 状态
        const config = this._levelConfigs.get(index);
        if (config) {
            this._levelConfigs.set(index, { ...config, completed: true });
        }
    }

    /**
     * 根据已完成的关卡 ID 列表，计算最高已完成关卡索引
     * @param completedLevelIds 服务端返回的已完成关卡 ID
     * @returns 最高已完成关卡的索引（0-based），无匹配返回 -1
     */
    getMaxCompletedIndex(completedLevelIds: string[]): number {
        if (!this._hasApiData || completedLevelIds.length === 0) {
            return -1;
        }

        const completedSet = new Set(completedLevelIds);
        let maxIndex = -1;

        for (let i = 0; i < this._apiData.length; i++) {
            if (completedSet.has(this._apiData[i].id)) {
                maxIndex = i;
            }
        }

        return maxIndex;
    }

    /**
     * 检查是否有 API 数据
     */
    hasApiData(): boolean {
        return this._hasApiData && this._apiData.length > 0;
    }

    /**
     * 检查指定关卡图片是否已加载
     * @param index 关卡索引
     */
    isLevelImageLoaded(index: number): boolean {
        return this._levelConfigs.has(index);
    }

    /**
     * 确保指定关卡资源已准备好
     * 如果资源未加载，会立即加载
     * @param index 关卡索引
     * @returns 加载的关卡配置，失败返回 null
     */
    async ensureLevelReady(index: number): Promise<RuntimeLevelConfig | null> {
        // 检查索引有效性
        if (index < 0 || index >= this._apiData.length) {
            console.warn(`[LevelDataManager] 关卡索引无效: ${index}`);
            return null;
        }

        // 检查缓存
        const cached = this._levelConfigs.get(index);
        if (cached) {
            return cached;
        }

        // 检查是否正在加载
        if (this._loadingLevels.has(index)) {
            console.log(`[LevelDataManager] 关卡 ${index} 正在加载中...`);
            return null;
        }

        // 开始加载
        this._loadingLevels.add(index);
        console.log(`[LevelDataManager] 开始加载关卡 ${index} 资源...`);

        const data = this._apiData[index];
        const [spriteFrame1, spriteFrame2] = await Promise.all([
            this._loadImage(data.image1Url),
            this._loadImage(data.image2Url),
        ]);
        this._loadingLevels.delete(index);

        if (!spriteFrame1) {
            console.error(`[LevelDataManager] 加载关卡 ${index} 图片1失败`);
            return null;
        }

        const config = this._createRuntimeConfig(data, spriteFrame1, spriteFrame2);
        this._levelConfigs.set(index, config);
        console.log(`[LevelDataManager] 关卡 ${index} 资源加载完成`);

        return config;
    }

    /**
     * 用 enter 接口返回的数据更新运行时关卡配置（填充答案和线索）
     */
    updateLevelDetails(index: number, details: { answer: string; image1Description: string | null; image2Description: string | null; punchline: string | null; hint1: string | null; hint2: string | null; hint3: string | null }): void {
        const config = this._levelConfigs.get(index);
        if (!config) {
            console.warn(`[LevelDataManager] 关卡 ${index} 配置不存在，无法更新详情`);
            return;
        }

        this._levelConfigs.set(index, {
            ...config,
            answer: details.answer,
            image1Description: details.image1Description ?? config.image1Description,
            image2Description: details.image2Description ?? config.image2Description,
            punchline: details.punchline ?? config.punchline,
            clue1: details.hint1 ?? null,
            clue2: details.hint2 ?? null,
            clue3: details.hint3 ?? null,
        });

        console.log(`[LevelDataManager] 关卡 ${index} 详情已更新`);
    }

    /**
     * 预加载下一关图片（静默加载，不阻塞）
     * 在进入当前关卡后调用，提前加载下一关资源
     * @param currentIndex 当前关卡索引
     */
    preloadNextLevel(currentIndex: number): void {
        const nextIndex = currentIndex + 1;

        // 检查是否有下一关
        if (nextIndex >= this._apiData.length) {
            console.log('[LevelDataManager] 没有下一关了');
            return;
        }

        // 检查是否已加载
        if (this._levelConfigs.has(nextIndex)) {
            console.log(`[LevelDataManager] 下一关 ${nextIndex} 已加载`);
            return;
        }

        // 检查是否正在加载
        if (this._loadingLevels.has(nextIndex)) {
            console.log(`[LevelDataManager] 下一关 ${nextIndex} 正在加载中`);
            return;
        }

        // 异步加载，不等待
        console.log(`[LevelDataManager] 开始预加载下一关 ${nextIndex}...`);
        this.ensureLevelReady(nextIndex).catch(err => {
            console.error(`[LevelDataManager] 预加载下一关失败:`, err);
        });
    }

    /**
     * 从 API 获取关卡数据（带重试机制）
     * @param onProgress 进度回调
     */
    private async _fetchApiData(onProgress?: ProgressCallback): Promise<ApiLevelData[] | null> {
        let lastError: Error | null = null;

        for (let attempt = 1; attempt <= this.API_RETRY_COUNT; attempt++) {
            const progress = (attempt - 1) / this.API_RETRY_COUNT * 0.3;

            try {
                onProgress?.(progress, `正在请求服务端数据 (第${attempt}次)...`);

                const response = await HttpUtil.get<ApiResponse>(API_ENDPOINTS.LEVELS, API_TIMEOUT.DEFAULT);

                if (!response.success) {
                    console.warn(`[LevelDataManager] API 返回失败, 消息: ${response.message}`);
                    lastError = new Error(response.message || 'API 返回失败');
                } else {
                    return response.data.levels;
                }
            } catch (error) {
                console.warn(`[LevelDataManager] 第${attempt}次请求失败:`, error);
                lastError = error as Error;
            }

            // 重试逻辑（无论是 response.success 为 false 还是抛出异常）
            if (attempt < this.API_RETRY_COUNT) {
                onProgress?.(progress + 0.05, `请求失败，正在重试...`);
                await this._delay(1000);
            }
        }

        console.error('[LevelDataManager] API 请求重试全部失败:', lastError);
        return null;
    }

    private _delay(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    /**
     * 创建运行时关卡配置
     * @param data API 关卡数据
     * @param spriteFrame1 已加载的图片1精灵帧
     * @param spriteFrame2 已加载的图片2精灵帧
     */
    private _createRuntimeConfig(data: ApiLevelData, spriteFrame1: SpriteFrame | null, spriteFrame2: SpriteFrame | null): RuntimeLevelConfig {
        return {
            id: data.id,
            name: `第${data.level}关`,
            spriteFrame1: spriteFrame1,
            spriteFrame2: spriteFrame2,
            image1Description: data.image1Description,
            image2Description: data.image2Description,
            punchline: data.punchline,
            clue1: data.hint1,
            clue2: data.hint2,
            clue3: data.hint3,
            answer: data.answer,
            completed: data.completed,
        };
    }

    /**
     * 加载远程图片为 SpriteFrame
     * @param url 图片 URL
     */
    private async _loadImage(url: string): Promise<SpriteFrame | null> {
        // 检查缓存
        const cached = this._imageCache.get(url);
        if (cached) {
            return cached;
        }

        return new Promise((resolve) => {
            assetManager.loadRemote<ImageAsset>(url, (err, imageAsset) => {
                if (err) {
                    console.error(`[LevelDataManager] 加载图片失败: ${url}`, err);
                    resolve(null);
                    return;
                }

                const texture = new Texture2D();
                texture.image = imageAsset;

                const spriteFrame = new SpriteFrame();
                spriteFrame.texture = texture;

                // 缓存
                this._imageCache.set(url, spriteFrame);

                resolve(spriteFrame);
            });
        });
    }

    /**
     * 清除缓存
     */
    clearCache(): void {
        this._apiData = [];
        this._levelConfigs.clear();
        this._loadingLevels.clear();
        this._hasApiData = false;
        this._imageCache.clear();
        console.log('[LevelDataManager] 缓存已清除');
    }
}
