'use strict';

var chunkW35VTQAW_js = require('../../chunk-W35VTQAW.js');
require('../../chunk-Z6ZWNWWR.js');
var AdmZip = require('adm-zip');
var crypto = require('crypto');
var promises = require('fs/promises');
var path = require('path');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var AdmZip__default = /*#__PURE__*/_interopDefault(AdmZip);
var path__default = /*#__PURE__*/_interopDefault(path);

var MMD_MODEL_ARCHIVE_MIME_TYPES = [
  "application/zip",
  "application/x-zip-compressed",
  "multipart/x-zip"
];
async function processMmdModelArchive(buffer, options) {
  const folderName = options.folderName ?? crypto.randomUUID();
  const targetDir = path__default.default.join(options.storageRoot, folderName);
  await promises.mkdir(targetDir, { recursive: true });
  const zip = new AdmZip__default.default(buffer);
  const entries = zip.getEntries();
  if (!entries.length) {
    await promises.rm(targetDir, { recursive: true, force: true });
    throw new Error("\u538B\u7F29\u5305\u4E3A\u7A7A\uFF0C\u8BF7\u68C0\u67E5\u4E0A\u4F20\u6587\u4EF6\u5185\u5BB9");
  }
  let modelRelativePath = null;
  let filesExtracted = 0;
  for (const entry of entries) {
    if (!entry.entryName || entry.entryName.startsWith("__MACOSX") || entry.entryName.endsWith(".DS_Store")) {
      continue;
    }
    const safeRelativePath = sanitizeEntryPath(entry.entryName);
    if (!safeRelativePath) {
      continue;
    }
    const destinationPath = path__default.default.join(targetDir, safeRelativePath);
    if (entry.isDirectory) {
      await promises.mkdir(destinationPath, { recursive: true });
      continue;
    }
    await promises.mkdir(path__default.default.dirname(destinationPath), { recursive: true });
    await promises.writeFile(destinationPath, entry.getData());
    filesExtracted += 1;
    const entryExt = path__default.default.extname(safeRelativePath).toLowerCase();
    if (!modelRelativePath && (entryExt === ".pmx" || entryExt === ".pmd")) {
      modelRelativePath = safeRelativePath.split(path__default.default.sep).join("/");
    }
  }
  if (!modelRelativePath) {
    await promises.rm(targetDir, { recursive: true, force: true });
    throw new Error("\u538B\u7F29\u5305\u4E2D\u672A\u627E\u5230 PMX/PMD \u6A21\u578B\u6587\u4EF6\uFF0C\u8BF7\u786E\u8BA4\u76EE\u5F55\u7ED3\u6784\u662F\u5426\u6B63\u786E");
  }
  const format = path__default.default.extname(modelRelativePath).slice(1).toLowerCase();
  const publicRoot = options.publicRoot ?? `/uploads/mmd/models`;
  const modelUrl = joinPublicPath(publicRoot, folderName, modelRelativePath);
  return {
    directory: targetDir,
    relativeDirectory: folderName,
    modelRelativePath,
    modelUrl,
    format,
    filesExtracted
  };
}
function sanitizeEntryPath(entryName) {
  const normalized = path__default.default.normalize(entryName).replace(/^(\.\.(\/|\\|$))+/, "");
  if (!normalized || normalized === "." || normalized.startsWith("..") || path__default.default.isAbsolute(normalized)) {
    return null;
  }
  return normalized;
}
function joinPublicPath(...segments) {
  return segments.map((segment) => segment.replace(/\/+/g, "/").replace(/^\//, "").replace(/\/$/, "")).filter(Boolean).join("/").replace(/\/{2,}/g, "/").replace(/^/, "/");
}

// src/mmd/server/playlistBuilder.ts
var defaultNormalizer = (value) => {
  if (!value) return "";
  if (value.startsWith("http://") || value.startsWith("https://")) {
    return value;
  }
  return value.startsWith("/") ? value : "/" + value;
};
function buildMmdPlaylistFromSources(options) {
  if (!options.models.length) {
    throw new Error("\u6784\u5EFA MMD \u64AD\u653E\u5217\u8868\u5931\u8D25\uFF1Amodels \u4E3A\u7A7A");
  }
  const limit = Math.max(1, Math.min(options.limit ?? options.models.length, options.models.length));
  const normalizeUrl = options.normalizeUrl ?? defaultNormalizer;
  const motions = options.motions ?? [];
  const hasMotions = motions.length > 0;
  const duration = options.nodeDuration ?? 30;
  const nodes = options.models.slice(0, limit).map((model, index) => {
    const motion = hasMotions ? motions[index % motions.length] : void 0;
    return {
      id: String(model.id ?? index),
      name: model.name,
      loop: options.loop ?? true,
      duration,
      thumbnail: model.thumbnailPath ? normalizeUrl(model.thumbnailPath) : void 0,
      resources: {
        modelPath: normalizeUrl(model.filePath),
        motionPath: motion ? normalizeUrl(motion.filePath) : void 0,
        cameraPath: void 0,
        audioPath: void 0,
        stageModelPath: void 0,
        additionalMotions: void 0
      }
    };
  });
  return {
    id: options.playlistId,
    name: options.playlistName ?? "MMD \u64AD\u653E\u5217\u8868 - " + options.playlistId,
    nodes,
    loop: options.loop ?? true,
    preload: options.preload ?? "next",
    autoPlay: options.autoPlay ?? true
  };
}

// src/mmd/server/mmdUpload.ts
var MMD_SUPPORTED_TYPES = {
  model: [...MMD_MODEL_ARCHIVE_MIME_TYPES],
  animation: ["application/octet-stream", "animation/vmd"],
  audio: ["audio/wav", "audio/mp3", "audio/mpeg", "audio/ogg"]
};
var MMD_FILE_EXTENSIONS = {
  model: [".zip"],
  animation: [".vmd"],
  audio: [".wav", ".mp3", ".ogg"]
};
async function uploadMmdResource(fileService, options) {
  const { file, resourceType, name, description, userId } = options;
  const ext = "." + file.name.split(".").pop()?.toLowerCase();
  const allowedExtensions = MMD_FILE_EXTENSIONS[resourceType];
  if (!allowedExtensions.includes(ext)) {
    throw new Error(
      "\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u6269\u5C55\u540D: " + ext + "\u3002\u652F\u6301\u7684\u683C\u5F0F: " + allowedExtensions.join(", ")
    );
  }
  const moduleId = "mmd-" + resourceType + "s";
  const metadata = await fileService.uploadFile({
    file,
    moduleId,
    businessId: "default",
    permission: "public",
    metadata: {
      uploadedBy: userId,
      uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
      originalFileName: file.name,
      resourceType,
      name,
      description: description || ""
    },
    needsProcessing: false
  });
  const format = ext.slice(1).toUpperCase();
  const fileUrl = metadata.cdnUrl || metadata.storagePath;
  return {
    id: metadata.id,
    name,
    url: fileUrl,
    filePath: metadata.storagePath,
    fileSize: metadata.size,
    type: resourceType,
    format,
    uploadTime: metadata.uploadTime,
    metadata
  };
}
async function uploadMmdModel(fileService, options) {
  const { file, storageRoot, publicRoot } = options;
  const baseResult = await uploadMmdResource(fileService, options);
  try {
    const fileBuffer = Buffer.from(await file.arrayBuffer());
    const archiveResult = await processMmdModelArchive(fileBuffer, {
      storageRoot,
      publicRoot,
      folderName: baseResult.id
    });
    return {
      ...baseResult,
      url: archiveResult.modelUrl,
      filePath: archiveResult.modelUrl,
      format: archiveResult.format.toUpperCase(),
      extractedPath: archiveResult.modelUrl
    };
  } catch (extractError) {
    console.error("\u6A21\u578B\u538B\u7F29\u5305\u5904\u7406\u5931\u8D25:", extractError);
    throw new Error(
      extractError instanceof Error ? extractError.message : "\u6A21\u578B\u538B\u7F29\u5305\u5904\u7406\u5931\u8D25"
    );
  }
}
async function batchUploadMmdResources(fileService, uploads) {
  const results = [];
  for (const uploadOptions of uploads) {
    try {
      const result = await uploadMmdResource(fileService, uploadOptions);
      results.push(result);
    } catch (error) {
      console.error("\u4E0A\u4F20\u5931\u8D25: " + uploadOptions.file.name, error);
    }
  }
  return results;
}

Object.defineProperty(exports, "mmdPlaylistNodes", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdPlaylistNodes; }
});
Object.defineProperty(exports, "mmdPlaylistNodesRelations", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdPlaylistNodesRelations; }
});
Object.defineProperty(exports, "mmdPlaylists", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdPlaylists; }
});
Object.defineProperty(exports, "mmdPlaylistsRelations", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdPlaylistsRelations; }
});
Object.defineProperty(exports, "mmdPresetItems", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdPresetItems; }
});
Object.defineProperty(exports, "mmdResourceOptions", {
  enumerable: true,
  get: function () { return chunkW35VTQAW_js.mmdResourceOptions; }
});
exports.MMD_FILE_EXTENSIONS = MMD_FILE_EXTENSIONS;
exports.MMD_MODEL_ARCHIVE_MIME_TYPES = MMD_MODEL_ARCHIVE_MIME_TYPES;
exports.MMD_SUPPORTED_TYPES = MMD_SUPPORTED_TYPES;
exports.batchUploadMmdResources = batchUploadMmdResources;
exports.buildMmdPlaylistFromSources = buildMmdPlaylistFromSources;
exports.processMmdModelArchive = processMmdModelArchive;
exports.uploadMmdModel = uploadMmdModel;
exports.uploadMmdResource = uploadMmdResource;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map