import { collectScenesAssets, printSceneDependencies, analyzeSceneDependencies } from '../analyzers/scene-asset-collector.js';
function shouldIncludeAsset(asset, scriptIds, requiredScriptIds, allowedAssetIds) {
    if (!asset) {
        return false;
    }
    if (asset.type === 'folder') {
        return false;
    }
    // PlayCanvas 源资产（source=true）不进入构建产物
    if (asset.source === true) {
        return false;
    }
    // 字体源文件（ttf/otf）不进入构建产物
    // 但如果 type === 'font' 且包含运行时数据（data.chars 或 data.info），
    // 说明这是 PlayCanvas 处理后的 MSDF/Bitmap 字体资源，必须保留
    const filename = asset.file?.filename?.toLowerCase?.();
    if (filename && (filename.endsWith('.ttf') || filename.endsWith('.otf'))) {
        if (asset.type === 'font' && (asset.data?.chars || asset.data?.info)) {
            // 这是已处理的字体数据资源（包含 MSDF chars 映射），保留
        }
        else {
            return false;
        }
    }
    // 脚本过滤：保留在 settings.scripts / WASM 关联 / 场景依赖(allowedAssetIds) 中的脚本资产
    if (asset.type === 'script' && asset.id != null) {
        const id = String(asset.id);
        return scriptIds.has(id) || requiredScriptIds.has(id) || (allowedAssetIds?.has(id) ?? false);
    }
    return true;
}
/**
 * 修复不完整的字体资源
 * 在 PlayCanvas/PlayCraft 项目中，可能存在两个同名的 font asset：
 * - 一个包含完整的 data（chars、info 等 MSDF 数据）
 * - 一个是空壳（被场景引用，但没有 data 和 file）
 * 此函数将有数据的 font asset 的 data 复制到空壳 font asset 中，
 * 并清除指向 .ttf/.otf 原始文件的 file 引用（运行时不需要加载这些文件，
 * 因为 MSDF 字符数据已经在 data.chars 中了）
 */
function fixIncompleteFontAssets(assets, allAssets) {
    // 收集有完整 data 的 font assets（按名称索引）
    const fontDataByName = {};
    for (const [, asset] of Object.entries(allAssets)) {
        const a = asset;
        if (a.type === 'font' && a.data?.chars && a.name) {
            fontDataByName[a.name] = a;
        }
    }
    // 修复没有 data 的 font assets
    let fixedCount = 0;
    for (const [, asset] of Object.entries(assets)) {
        const a = asset;
        if (a.type !== 'font') {
            continue;
        }
        // 如果 font asset 没有 chars 数据，尝试从同名的有数据的 font asset 中获取
        if (!a.data?.chars) {
            const donor = fontDataByName[a.name];
            if (donor) {
                a.data = donor.data;
                fixedCount++;
            }
        }
        // 清除指向 .ttf/.otf 原始文件的 file 引用
        // PlayCanvas 运行时会尝试 fetch file.url，但 .ttf 不是 font data JSON
        // 实际的 MSDF chars 数据已经在 data.chars 中，不需要额外加载
        const fileUrl = a.file?.url?.toLowerCase?.() || '';
        const fileName = a.file?.filename?.toLowerCase?.() || '';
        if (fileUrl.endsWith('.ttf') || fileUrl.endsWith('.otf') ||
            fileName.endsWith('.ttf') || fileName.endsWith('.otf')) {
            delete a.file;
        }
    }
    if (fixedCount > 0) {
        console.log(`[ConfigGenerator] 修复了 ${fixedCount} 个不完整的字体资源`);
    }
}
function collectRequiredScriptIds(assets) {
    const required = new Set();
    for (const asset of Object.values(assets)) {
        const assetData = asset;
        if (assetData?.type === 'wasm' && assetData?.data) {
            const glueId = assetData.data.glueScriptId;
            const fallbackId = assetData.data.fallbackScriptId;
            if (glueId != null) {
                required.add(String(glueId));
            }
            if (fallbackId != null) {
                required.add(String(fallbackId));
            }
        }
    }
    return required;
}
/**
 * 精简资源元数据，删除运行时不需要的字段
 * 这可以显著减少 config.json 的体积（通常减少 30-50%）
 */
function stripAssetMetadata(asset) {
    if (!asset)
        return asset;
    // 创建浅拷贝
    const stripped = { ...asset };
    // 删除编辑器专用字段
    delete stripped.tags; // 编辑器标签
    delete stripped.i18n; // 国际化数据
    delete stripped.meta; // 编辑器元数据
    delete stripped.thumbnails; // 缩略图
    delete stripped.revision; // 版本号
    delete stripped.created_at; // 创建时间
    delete stripped.updated_at; // 更新时间
    delete stripped.user; // 用户信息
    delete stripped.branch_id; // 分支ID
    // 精简 file 对象（保留运行时需要的字段）
    if (stripped.file) {
        const file = stripped.file;
        stripped.file = {
            url: file.url,
            filename: file.filename,
            size: file.size,
            hash: file.hash,
            variants: file.variants, // 纹理变体（如压缩格式）
        };
    }
    // 精简 data 对象（根据资源类型保留必要字段）
    if (stripped.data) {
        const data = stripped.data;
        const type = stripped.type;
        // 根据资源类型精简 data
        switch (type) {
            case 'texture':
                // 纹理只需要基本配置
                stripped.data = {
                    minfilter: data.minfilter,
                    magfilter: data.magfilter,
                    addressu: data.addressu,
                    addressv: data.addressv,
                    mipmaps: data.mipmaps,
                    anisotropy: data.anisotropy,
                    rgbm: data.rgbm,
                };
                break;
            case 'cubemap':
                // 立方体贴图
                stripped.data = {
                    textures: data.textures,
                    minfilter: data.minfilter,
                    magfilter: data.magfilter,
                    anisotropy: data.anisotropy,
                    rgbm: data.rgbm,
                };
                break;
            case 'material':
                // 材质需要完整的 data（但可以删除一些编辑器字段）
                const materialData = { ...data };
                if (materialData.editor) {
                    delete materialData.editor;
                }
                stripped.data = materialData;
                break;
            case 'model':
            case 'container':
                // 模型和容器需要 mapping 信息
                stripped.data = {
                    mapping: data.mapping,
                    area: data.area,
                };
                break;
            case 'animation':
                // 动画需要 duration
                stripped.data = {
                    duration: data.duration,
                };
                break;
            case 'audio':
                // 音频需要 duration
                stripped.data = {
                    duration: data.duration,
                };
                break;
            case 'script':
                // 脚本需要 scripts 和 loading_type
                stripped.data = {
                    scripts: data.scripts,
                    loading_type: data.loading_type,
                    order: data.order,
                };
                break;
            case 'json':
            case 'text':
            case 'html':
            case 'css':
            case 'shader':
                // 这些类型通常不需要 data
                delete stripped.data;
                break;
            case 'font':
                // 字体需要 info
                stripped.data = {
                    info: data.info,
                };
                break;
            case 'sprite':
                // 精灵需要 frameKeys, pixelsPerUnit, renderMode
                stripped.data = {
                    frameKeys: data.frameKeys,
                    pixelsPerUnit: data.pixelsPerUnit,
                    renderMode: data.renderMode,
                    textureAtlasAsset: data.textureAtlasAsset,
                };
                break;
            case 'textureatlas':
                // 纹理图集需要 frames
                stripped.data = {
                    frames: data.frames,
                };
                break;
            case 'template':
                // 模板需要完整的 data
                // 不做精简
                break;
            case 'wasm':
                // WASM 需要 glueScriptId 和 fallbackScriptId
                stripped.data = {
                    glueScriptId: data.glueScriptId,
                    fallbackScriptId: data.fallbackScriptId,
                    moduleName: data.moduleName,
                };
                break;
            default:
                // 其他类型保留原始 data
                break;
        }
    }
    return stripped;
}
/**
 * 生成 PlayCanvas 构建产物格式的 config.json
 */
export async function generateConfig(projectConfig, options) {
    if (projectConfig.format === 'playcanvas') {
        const pcProject = projectConfig;
        // 从 PlayCanvas 项目格式生成 config.json
        const config = {
            application_properties: pcProject.project.settings || {},
        };
        // 兼容官方构建：确保 libraries/batchGroups 为数组
        if (!Array.isArray(config.application_properties.libraries)) {
            config.application_properties.libraries = [];
        }
        if (!Array.isArray(config.application_properties.batchGroups)) {
            config.application_properties.batchGroups = [];
        }
        // 处理场景
        let allScenes = [];
        if (pcProject.scenes) {
            allScenes = Array.isArray(pcProject.scenes)
                ? pcProject.scenes
                : Object.entries(pcProject.scenes).map(([keyId, scene]) => {
                    // keyId 是场景文件名使用的 ID（如 "2388047"）
                    // scene 中可能也有 id 字段（如 "2415082"），但场景文件名应该用 keyId
                    return { ...scene, sceneFileId: keyId };
                });
        }
        // 场景过滤：如果指定了选中的场景，则只包含这些场景
        let selectedScenes = allScenes;
        if (options?.selectedScenes && options.selectedScenes.length > 0) {
            selectedScenes = allScenes.filter(scene => {
                const sceneId = String(scene.id || scene.scene);
                const sceneName = scene.name || '';
                return options.selectedScenes.some(selected => selected === sceneId || selected === sceneName);
            });
            // 验证：检查是否所有指定的场景都存在
            if (selectedScenes.length === 0) {
                const availableScenes = allScenes.map(s => s.name || s.id).join(', ');
                // 尝试找到默认场景（主场景或第一个场景）
                const defaultScene = allScenes.find(s => s.isMain === true) || allScenes[0];
                if (defaultScene && allScenes.length > 0) {
                    console.warn(`\n⚠️  警告: 未找到指定的场景，使用默认场景\n` +
                        `   指定的场景: ${options.selectedScenes.join(', ')}\n` +
                        `   可用的场景: ${availableScenes}\n` +
                        `   默认场景: ${defaultScene.name || defaultScene.id}${defaultScene.isMain ? ' (主场景)' : ''}`);
                    selectedScenes = [defaultScene];
                }
                else {
                    throw new Error(`❌ 未找到任何匹配的场景，且项目中没有可用场景！\n` +
                        `   指定的场景: ${options.selectedScenes.join(', ')}\n` +
                        `   提示: 场景名称区分大小写，请检查拼写是否正确`);
                }
            }
            else {
                // 检查是否有指定的场景未找到（部分匹配）
                const foundSceneNames = new Set(selectedScenes.map(s => s.name));
                const foundSceneIds = new Set(selectedScenes.map(s => String(s.id || s.scene)));
                const notFoundScenes = options.selectedScenes.filter(selected => !foundSceneNames.has(selected) && !foundSceneIds.has(selected));
                if (notFoundScenes.length > 0) {
                    const availableScenes = allScenes.map(s => s.name || s.id).join(', ');
                    console.warn(`\n⚠️  警告: 以下场景未找到，将忽略:\n` +
                        `   ${notFoundScenes.join(', ')}\n` +
                        `   可用的场景: ${availableScenes}`);
                }
            }
            console.log(`\n🎬 场景过滤:`);
            console.log(`  - 总场景数: ${allScenes.length}`);
            console.log(`  - 选中场景: ${selectedScenes.length}`);
            selectedScenes.forEach(scene => {
                console.log(`    • ${scene.name || scene.id}${scene.isMain ? ' (主场景)' : ''}`);
            });
        }
        config.scenes = selectedScenes.map((scene) => ({
            name: scene.name || scene.sceneFileId || scene.id,
            // 场景文件名优先使用 sceneFileId（来自 scenes.json 的 key）
            url: scene.url || scene.file || `${scene.sceneFileId || scene.id}.json`,
        }));
        // 处理资产：基于场景过滤
        if (pcProject.assets) {
            const scriptIds = new Set((pcProject.project.settings?.scripts || []).map((id) => String(id)));
            const requiredScriptIds = collectRequiredScriptIds(pcProject.assets);
            let allowedAssetIds = null;
            // 如果启用了场景过滤，分析场景依赖
            if (options?.selectedScenes && options.selectedScenes.length > 0 && selectedScenes.length > 0) {
                console.log(`\n🔍 分析场景资源依赖...`);
                // scenes.json 中的场景数据已经包含完整的 entities 字段，直接使用
                const fullScenes = selectedScenes;
                allowedAssetIds = await collectScenesAssets(fullScenes, pcProject.assets, scriptIds);
                // 打印每个场景的依赖统计
                for (const scene of fullScenes) {
                    const deps = await analyzeSceneDependencies(scene, pcProject.assets);
                    printSceneDependencies(deps);
                }
                console.log(`\n📊 资源过滤统计:`);
                console.log(`  - 总资源数: ${Object.keys(pcProject.assets).length}`);
                console.log(`  - 全局脚本: ${scriptIds.size}`);
                console.log(`  - 场景依赖: ${allowedAssetIds.size}`);
                console.log(`  - 将节省: ${Object.keys(pcProject.assets).length - allowedAssetIds.size} 个资源 (${((1 - allowedAssetIds.size / Object.keys(pcProject.assets).length) * 100).toFixed(1)}%)`);
            }
            const filtered = {};
            const shouldStrip = options?.stripMetadata === true; // 默认禁用精简（保留所有字段以确保运行时兼容性）
            for (const [assetId, asset] of Object.entries(pcProject.assets)) {
                // 基本过滤（非运行时资产）
                if (!shouldIncludeAsset(asset, scriptIds, requiredScriptIds, allowedAssetIds)) {
                    continue;
                }
                // template 资产始终包含（因为它们通常是运行时通过 assets.find() 动态引用的）
                const assetAny = asset;
                if (assetAny.type === 'template') {
                    filtered[assetId] = shouldStrip ? stripAssetMetadata(asset) : asset;
                    continue;
                }
                // 场景过滤：如果启用，只包含场景依赖的资源
                if (allowedAssetIds && !allowedAssetIds.has(assetId)) {
                    continue;
                }
                // 精简资源元数据（如果启用）
                filtered[assetId] = shouldStrip ? stripAssetMetadata(asset) : asset;
            }
            config.assets = filtered;
            // 打印过滤结果汇总
            {
                const scriptCount = Object.values(filtered).filter((a) => a.type === 'script').length;
                console.log(`[configGen] config.assets: ${Object.keys(filtered).length} 个资源 (其中 ${scriptCount} 个脚本)`);
            }
            // 修复不完整的字体资源（从同名的有数据的 font asset 中补充 data）
            fixIncompleteFontAssets(config.assets, pcProject.assets);
            // 输出精简统计
            if (shouldStrip && Object.keys(pcProject.assets).length > 0) {
                const originalSize = JSON.stringify(pcProject.assets).length;
                const strippedSize = JSON.stringify(filtered).length;
                const savedBytes = originalSize - strippedSize;
                const savedPercent = ((savedBytes / originalSize) * 100).toFixed(1);
                console.log(`\n🗜️  元数据精简统计:`);
                console.log(`  - 原始大小: ${(originalSize / 1024).toFixed(1)} KB`);
                console.log(`  - 精简后: ${(strippedSize / 1024).toFixed(1)} KB`);
                console.log(`  - 节省: ${(savedBytes / 1024).toFixed(1)} KB (${savedPercent}%)`);
            }
        }
        return config;
    }
    else {
        // PlayCraft 格式
        const pcProject = projectConfig;
        const config = {
            application_properties: pcProject.manifest.settings || {},
        };
        // 兼容官方构建：确保 libraries/batchGroups 为数组
        if (!Array.isArray(config.application_properties.libraries)) {
            config.application_properties.libraries = [];
        }
        if (!Array.isArray(config.application_properties.batchGroups)) {
            config.application_properties.batchGroups = [];
        }
        // 处理场景
        let allScenes = pcProject.scenes || [];
        let selectedScenes = allScenes;
        if (options?.selectedScenes && options.selectedScenes.length > 0 && allScenes.length > 0) {
            selectedScenes = allScenes.filter(scene => {
                const sceneId = String(scene.id || scene.scene);
                const sceneName = scene.name || '';
                return options.selectedScenes.some(selected => selected === sceneId || selected === sceneName);
            });
            // 验证：检查是否所有指定的场景都存在
            if (selectedScenes.length === 0) {
                const availableScenes = allScenes.map(s => s.name || s.id).join(', ');
                // 尝试找到默认场景（主场景或第一个场景）
                const defaultScene = allScenes.find(s => s.isMain === true) || allScenes[0];
                if (defaultScene && allScenes.length > 0) {
                    console.warn(`\n⚠️  警告: 未找到指定的场景，使用默认场景\n` +
                        `   指定的场景: ${options.selectedScenes.join(', ')}\n` +
                        `   可用的场景: ${availableScenes}\n` +
                        `   默认场景: ${defaultScene.name || defaultScene.id}${defaultScene.isMain ? ' (主场景)' : ''}`);
                    selectedScenes = [defaultScene];
                }
                else {
                    throw new Error(`❌ 未找到任何匹配的场景，且项目中没有可用场景！\n` +
                        `   指定的场景: ${options.selectedScenes.join(', ')}\n` +
                        `   提示: 场景名称区分大小写，请检查拼写是否正确`);
                }
            }
            else {
                // 检查是否有指定的场景未找到（部分匹配）
                const foundSceneNames = new Set(selectedScenes.map(s => s.name));
                const foundSceneIds = new Set(selectedScenes.map(s => String(s.id || s.scene)));
                const notFoundScenes = options.selectedScenes.filter(selected => !foundSceneNames.has(selected) && !foundSceneIds.has(selected));
                if (notFoundScenes.length > 0) {
                    const availableScenes = allScenes.map(s => s.name || s.id).join(', ');
                    console.warn(`\n⚠️  警告: 以下场景未找到，将忽略:\n` +
                        `   ${notFoundScenes.join(', ')}\n` +
                        `   可用的场景: ${availableScenes}`);
                }
            }
            console.log(`\n🎬 场景过滤:`);
            console.log(`  - 总场景数: ${allScenes.length}`);
            console.log(`  - 选中场景: ${selectedScenes.length}`);
            selectedScenes.forEach(scene => {
                console.log(`    • ${scene.name || scene.id}${scene.isMain ? ' (主场景)' : ''}`);
            });
        }
        if (selectedScenes.length > 0) {
            config.scenes = selectedScenes.map((scene) => ({
                name: scene.name || scene.id,
                url: scene.url || `${scene.id || 'scene'}.json`,
            }));
        }
        // 处理资产：基于场景过滤
        if (pcProject.assets) {
            const scriptIds = new Set((pcProject.manifest.settings?.scripts || []).map((id) => String(id)));
            const requiredScriptIds = collectRequiredScriptIds(pcProject.assets);
            let allowedAssetIds = null;
            // 如果启用了场景过滤，分析场景依赖
            if (options?.selectedScenes && options.selectedScenes.length > 0 && selectedScenes.length > 0) {
                console.log(`\n🔍 分析场景资源依赖...`);
                allowedAssetIds = await collectScenesAssets(selectedScenes, pcProject.assets, scriptIds);
                // 打印每个场景的依赖统计
                for (const scene of selectedScenes) {
                    const deps = await analyzeSceneDependencies(scene, pcProject.assets);
                    printSceneDependencies(deps);
                }
                console.log(`\n📊 资源过滤统计:`);
                console.log(`  - 总资源数: ${Object.keys(pcProject.assets).length}`);
                console.log(`  - 全局脚本: ${scriptIds.size}`);
                console.log(`  - 场景依赖: ${allowedAssetIds.size}`);
                console.log(`  - 将节省: ${Object.keys(pcProject.assets).length - allowedAssetIds.size} 个资源 (${((1 - allowedAssetIds.size / Object.keys(pcProject.assets).length) * 100).toFixed(1)}%)`);
            }
            const filtered = {};
            const shouldStrip = options?.stripMetadata === true; // 默认禁用精简（保留所有字段以确保运行时兼容性）
            for (const [assetId, asset] of Object.entries(pcProject.assets)) {
                // 基本过滤（非运行时资产）
                if (!shouldIncludeAsset(asset, scriptIds, requiredScriptIds, allowedAssetIds)) {
                    continue;
                }
                // template 资产始终包含（因为它们通常是运行时通过 assets.find() 动态引用的）
                const assetAny = asset;
                if (assetAny.type === 'template') {
                    filtered[assetId] = shouldStrip ? stripAssetMetadata(asset) : asset;
                    continue;
                }
                // 场景过滤：如果启用，只包含场景依赖的资源
                if (allowedAssetIds && !allowedAssetIds.has(assetId)) {
                    continue;
                }
                // 精简资源元数据（如果启用）
                filtered[assetId] = shouldStrip ? stripAssetMetadata(asset) : asset;
            }
            config.assets = filtered;
            // 修复不完整的字体资源（从同名的有数据的 font asset 中补充 data）
            fixIncompleteFontAssets(config.assets, pcProject.assets);
            // 输出精简统计
            if (shouldStrip && Object.keys(pcProject.assets).length > 0) {
                const originalSize = JSON.stringify(pcProject.assets).length;
                const strippedSize = JSON.stringify(filtered).length;
                const savedBytes = originalSize - strippedSize;
                const savedPercent = ((savedBytes / originalSize) * 100).toFixed(1);
                console.log(`\n🗜️  元数据精简统计:`);
                console.log(`  - 原始大小: ${(originalSize / 1024).toFixed(1)} KB`);
                console.log(`  - 精简后: ${(strippedSize / 1024).toFixed(1)} KB`);
                console.log(`  - 节省: ${(savedBytes / 1024).toFixed(1)} KB (${savedPercent}%)`);
            }
        }
        return config;
    }
}
