import fs from 'fs/promises';
import path from 'path';
/**
 * 将 PlayCraft git 仓库中的 API URL 转换为本地文件路径
 * API URL 格式: /api/projects/{id}/files/assets/textures/ball.png?branchId=master
 * 本地路径格式: assets/textures/ball.png
 *
 * 也处理 PlayCraft 的 treePath 格式:
 * path 字段: assets/assets/{folderId}/filename
 * 本地路径: assets/{folderName}/filename
 */
function resolvePlayCraftAssetUrl(asset, projectDir) {
    const fileUrl = asset.file?.url;
    if (!fileUrl || typeof fileUrl !== 'string')
        return null;
    // 如果已经是相对路径且不是 API URL，直接返回
    if (!fileUrl.startsWith('/api/') && !fileUrl.startsWith('http')) {
        return fileUrl;
    }
    // 解析 API URL: /api/projects/{id}/files/{path}?branchId=...
    const match = fileUrl.match(/\/api\/projects\/\d+\/files\/(.+?)(?:\?|$)/);
    if (match) {
        const relativePath = decodeURIComponent(match[1]);
        return relativePath;
    }
    return null;
}
/**
 * 修正 PlayCraft 项目中所有资源的 file.url
 * 将 API URL 转换为本地相对路径，并验证文件是否存在
 */
async function resolvePlayCraftUrls(assets, projectDir) {
    let resolvedCount = 0;
    let notFoundCount = 0;
    for (const [assetId, asset] of Object.entries(assets)) {
        const assetData = asset;
        if (!assetData.file?.url)
            continue;
        const originalUrl = assetData.file.url;
        const localPath = resolvePlayCraftAssetUrl(assetData, projectDir);
        if (!localPath)
            continue;
        // 如果 URL 已经更改为本地路径
        if (localPath !== originalUrl) {
            // 验证文件是否存在
            const absPath = path.join(projectDir, localPath);
            try {
                await fs.access(absPath);
                assetData.file.url = localPath;
                resolvedCount++;
            }
            catch {
                // 文件不存在，尝试使用 asset 的 path 字段中的 treePath 信息
                // PlayCraft 的 path 字段可能是 "assets/assets/{folderId}/{filename}"
                if (assetData.path) {
                    const pathUrl = assetData.path;
                    const pathAbs = path.join(projectDir, pathUrl);
                    try {
                        await fs.access(pathAbs);
                        assetData.file.url = pathUrl;
                        resolvedCount++;
                    }
                    catch {
                        notFoundCount++;
                    }
                }
                else {
                    notFoundCount++;
                }
            }
        }
    }
    if (resolvedCount > 0 || notFoundCount > 0) {
        console.log(`[PlayCraftLoader] 解析资源 URL: ${resolvedCount} 个成功${notFoundCount > 0 ? `, ${notFoundCount} 个未找到` : ''}`);
    }
}
/**
 * PlayCanvas 场景 settings 的默认值
 * 当场景文件中缺少这些设置时，使用这些默认值以确保正常渲染
 */
const DEFAULT_SCENE_SETTINGS = {
    render: {
        skybox: null,
        fog: 'none',
        fog_color: [0, 0, 0],
        fog_start: 1,
        fog_end: 1000,
        fog_density: 0.01,
        tonemapping: 0,
        exposure: 1,
        gamma_correction: 1,
        global_ambient: [0.2, 0.2, 0.2],
        lightmapSizeMultiplier: 16,
        lightmapMaxResolution: 2048,
        lightmapMode: 0,
        skyType: 'infinite',
        skyMeshPosition: [0, 0, 0],
        skyMeshRotation: [0, 0, 0],
        skyMeshScale: [100, 100, 100],
        skyCenter: [0, 0.1, 0],
        skyboxIntensity: 1,
        skyboxMip: 0,
        skyboxRotation: [0, 0, 0],
        lightmapFilterEnabled: false,
        lightmapFilterRange: 10,
        lightmapFilterSmoothness: 0.2,
        ambientBake: false,
        ambientBakeNumSamples: 1,
        ambientBakeSpherePart: 0.4,
        ambientBakeOcclusionBrightness: 0,
        ambientBakeOcclusionContrast: 0,
        clusteredLightingEnabled: true,
        lightingCells: [10, 3, 10],
        lightingMaxLightsPerCell: 255,
        lightingCookieAtlasResolution: 2048,
        lightingShadowAtlasResolution: 2048,
        lightingShadowType: 0,
        lightingCookiesEnabled: false,
        lightingAreaLightsEnabled: false,
        lightingShadowsEnabled: true,
    },
    physics: {
        gravity: [0, -9.8, 0],
    },
    priority_scripts: [],
};
/**
 * 深度合并对象：target 中缺少的字段从 source 补全
 * 只补全 target 中不存在的字段，不覆盖已有值
 */
function deepMergeDefaults(target, source) {
    if (!source || typeof source !== 'object')
        return target;
    if (!target || typeof target !== 'object')
        return { ...source };
    const result = Array.isArray(target) ? [...target] : { ...target };
    for (const key of Object.keys(source)) {
        if (!(key in result)) {
            result[key] = source[key];
        }
        else if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key]) &&
            typeof result[key] === 'object' && result[key] !== null && !Array.isArray(result[key])) {
            result[key] = deepMergeDefaults(result[key], source[key]);
        }
    }
    return result;
}
/**
 * 补全场景 settings
 * 优先从主场景继承 settings，否则使用默认值
 */
function ensureSceneSettings(scenes, mainSceneId) {
    // 找到主场景（settings 最完整的场景）
    const mainScene = mainSceneId
        ? scenes.find(s => String(s.id) === mainSceneId)
        : scenes[0];
    // 使用主场景的 settings 作为基础，再补上默认值
    const baseSettings = mainScene?.settings
        ? deepMergeDefaults(mainScene.settings, DEFAULT_SCENE_SETTINGS)
        : DEFAULT_SCENE_SETTINGS;
    let fixedCount = 0;
    for (const scene of scenes) {
        const originalKeys = Object.keys(scene.settings?.render || {});
        // 判断 settings 是否不完整（render 中少于 5 个字段认为不完整）
        if (!scene.settings || !scene.settings.render || originalKeys.length < 5) {
            scene.settings = deepMergeDefaults(scene.settings || {}, baseSettings);
            fixedCount++;
            const newKeys = Object.keys(scene.settings.render || {});
            console.log(`[PlayCraftLoader] 补全场景 "${scene.name}" (${scene.id}) 的 settings: ${originalKeys.length} → ${newKeys.length} 个渲染属性`);
        }
    }
    if (fixedCount > 0) {
        console.log(`[PlayCraftLoader] 共补全了 ${fixedCount} 个场景的 settings`);
    }
}
/**
 * 加载 PlayCraft 源代码项目
 */
export async function loadPlayCraftProject(projectDir) {
    // 1. 读取 manifest.json
    const manifestContent = await fs.readFile(path.join(projectDir, 'manifest.json'), 'utf-8');
    const manifest = JSON.parse(manifestContent);
    // 1.1 从 settings/project.json 加载完整项目设置
    // manifest.settings 可能只包含 importMap 等少量字段，缺少 width/height/fillMode 等关键应用属性
    // 需要始终尝试加载 settings/project.json 并合并
    const needsFullSettings = !manifest.settings || !manifest.settings.width || !manifest.settings.fillMode;
    if (needsFullSettings) {
        const settingsPaths = [
            path.join(projectDir, 'settings', 'project.json'),
            path.join(projectDir, 'project.json'),
        ];
        for (const settingsPath of settingsPaths) {
            try {
                const settingsContent = await fs.readFile(settingsPath, 'utf-8');
                const projectData = JSON.parse(settingsContent);
                if (projectData.settings) {
                    // 合并：settings/project.json 的完整设置为基础，manifest.settings 中的字段优先
                    manifest.settings = { ...projectData.settings, ...(manifest.settings || {}) };
                    console.log(`[PlayCraftLoader] 从 ${path.relative(projectDir, settingsPath)} 加载并合并项目设置`);
                    break;
                }
            }
            catch {
                // 继续尝试下一个路径
            }
        }
    }
    // 2. 读取场景文件
    const scenesDir = path.join(projectDir, 'scenes');
    let scenes = [];
    // 从 manifest 中获取场景元信息（包含 isMain 标记）
    const manifestScenes = manifest.scenes || [];
    const mainSceneId = manifestScenes.find((s) => s.isMain)?.id?.toString();
    try {
        const sceneFiles = await fs.readdir(scenesDir);
        // 支持 .scene.json 和 .json 两种格式
        const jsonFiles = sceneFiles.filter(f => f.endsWith('.json'));
        scenes = await Promise.all(jsonFiles.map(async (f) => {
            const content = await fs.readFile(path.join(scenesDir, f), 'utf-8');
            const scene = JSON.parse(content);
            // 从文件名提取场景 ID（如 20000078.json → 20000078）
            if (!scene.id) {
                scene.id = f.replace(/\.scene\.json$/, '').replace(/\.json$/, '');
            }
            // 从 manifest 中补充场景元信息（名称、isMain 等）
            const manifestScene = manifestScenes.find((ms) => String(ms.id) === String(scene.id));
            if (manifestScene) {
                if (!scene.name || scene.name === 'Untitled') {
                    scene.name = manifestScene.name || scene.name;
                }
                if (manifestScene.isMain) {
                    scene.isMain = true;
                }
            }
            return scene;
        }));
        // 排序：主场景排在第一个（PlayCanvas 引擎加载 config.scenes[0] 作为默认场景）
        if (mainSceneId) {
            scenes.sort((a, b) => {
                const aIsMain = String(a.id) === mainSceneId ? -1 : 0;
                const bIsMain = String(b.id) === mainSceneId ? -1 : 0;
                return aIsMain - bIsMain;
            });
        }
        if (scenes.length > 0) {
            console.log(`[PlayCraftLoader] 加载了 ${scenes.length} 个场景文件${mainSceneId ? `，主场景: ${mainSceneId}` : ''}`);
        }
        // 补全不完整的场景 settings
        // PlayCraft Editor 中，非主场景可能只保存了修改过的设置字段，
        // 其余字段在运行时由 Editor 补充默认值。打包时需要手动补全。
        if (scenes.length > 0) {
            ensureSceneSettings(scenes, mainSceneId);
        }
    }
    catch (error) {
        // scenes 目录可能不存在
        console.warn('[PlayCraftLoader] 警告: scenes 目录不存在，跳过场景加载');
    }
    // 3. 读取 assets.json（PlayCraft 保留的 PlayCanvas 兼容层）
    let assets = {};
    const assetsJsonPath = path.join(projectDir, 'assets', 'assets.json');
    try {
        const assetsContent = await fs.readFile(assetsJsonPath, 'utf-8');
        assets = JSON.parse(assetsContent);
    }
    catch (error) {
        // assets.json 可能不存在，尝试从 manifest 中读取
        if (manifest.assets && Array.isArray(manifest.assets)) {
            // 转换为 PlayCanvas 格式（key-value 对象）
            assets = {};
            for (const asset of manifest.assets) {
                if (asset.id) {
                    assets[asset.id] = asset;
                }
            }
        }
    }
    // 4. 修正 PlayCraft 资源 URL（将 API URL 转换为本地路径）
    await resolvePlayCraftUrls(assets, projectDir);
    return {
        manifest,
        scenes,
        assets,
        format: 'playcraft',
    };
}
