/**
 * 统一运行时包定义 — 本地 static/unity 与 OSS unitycdndir 内容完全一致。
 *
 * 运行时包（唯一真相）:
 *   Build/
 *   StreamingAssets/
 *   levels-database.json
 *   levels-database.json.br
 *   levels-db-index.json
 *   levels-db-index.json.br
 *   StreamingAssets/aa/levels-db/
 *
 * 不含 index.html / TemplateData（仅 standalone-player 独立调试页使用）
 */
const fs = require('fs');
const path = require('path');

const RUNTIME_ROOT_FILES = [
  'levels-database.json',
  'levels-database.json.br',
  'levels-db-index.json',
  'levels-db-index.json.br',
];
const RUNTIME_DIRS = ['Build', 'StreamingAssets'];

function walkFiles(root, bucket, prefix = '') {
  if (!fs.existsSync(root)) return;
  for (const ent of fs.readdirSync(root, { withFileTypes: true })) {
    if (ent.name === '.DS_Store') continue;
    const rel = prefix ? `${prefix}/${ent.name}` : ent.name;
    const full = path.join(root, ent.name);
    if (ent.isDirectory()) walkFiles(full, bucket, rel);
    else bucket.push({ rel, full, size: fs.statSync(full).size });
  }
}

/** 列出运行时包内所有相对路径（用于 manifest / 校验） */
function listRuntimeFiles(packDir) {
  const files = [];
  for (const dir of RUNTIME_DIRS) {
    walkFiles(path.join(packDir, dir), files, dir);
  }
  for (const name of RUNTIME_ROOT_FILES) {
    const full = path.join(packDir, name);
    if (fs.existsSync(full)) {
      files.push({ rel: name, full, size: fs.statSync(full).size });
    }
  }
  return files.sort((a, b) => a.rel.localeCompare(b.rel));
}

function bundleNamesFromCatalog(catalogPath) {
  if (!fs.existsSync(catalogPath)) return [];
  const catalog = JSON.parse(fs.readFileSync(catalogPath, 'utf8'));
  return [...new Set(
    (catalog.m_InternalIds || [])
      .filter((id) => String(id).includes('.bundle'))
      .map((id) => String(id).split('/').pop()),
  )].sort();
}

function assertRuntimePack(packDir, opts) {
  opts = opts || {};
  const loader = path.join(packDir, 'Build/mstest5.loader.js');
  const catalog = path.join(packDir, 'StreamingAssets/aa/catalog.json');
  const levelsManifest = path.join(packDir, 'StreamingAssets/aa/levels-manifest.json');
  if (!fs.existsSync(loader)) {
    throw new Error(`缺少运行时包: ${loader}`);
  }
  if (!fs.existsSync(catalog)) {
    throw new Error(`缺少运行时包: ${catalog}`);
  }
  if (!fs.existsSync(path.join(packDir, 'levels-db-index.json'))) {
    throw new Error(`缺少运行时包: ${path.join(packDir, 'levels-db-index.json')}`);
  }
  if (!fs.existsSync(path.join(packDir, 'levels-database.json'))) {
    throw new Error(`缺少运行时包: ${path.join(packDir, 'levels-database.json')}`);
  }
  const names = bundleNamesFromCatalog(catalog);
  if (opts.requireLevelsBundle && !names.some((n) => n.includes('levels_all'))) {
    throw new Error('catalog 缺少 levels_all 分包');
  }
  if (opts.requireLevelsManifest && !fs.existsSync(levelsManifest)) {
    throw new Error(`缺少运行时包: ${levelsManifest}`);
  }
  if (opts.requireLevelsManifest) {
    const manifest = JSON.parse(fs.readFileSync(levelsManifest, 'utf8'));
    const count = Object.keys(manifest.levels || {}).length;
    if (count < 1) throw new Error('levels-manifest.json 无关卡条目');
  }
  for (const name of names) {
    const p = path.join(packDir, 'StreamingAssets/aa/WebGL', name);
    if (!fs.existsSync(p) || fs.statSync(p).size < 100) {
      throw new Error(`bundle 无效: ${p}`);
    }
  }
}

module.exports = {
  RUNTIME_ROOT_FILES,
  RUNTIME_DIRS,
  walkFiles,
  listRuntimeFiles,
  bundleNamesFromCatalog,
  assertRuntimePack,
};
