import fs from "node:fs/promises";
import path from "node:path";
import { dataDir } from "./infra/config.js";
const SHARED_DIR = path.join(dataDir, "shared-assets");
const CATEGORIES = ["characters", "scenes", "music", "templates", "branding", "general"];
export function sanitizeFilename(name) {
    const clean = path.basename(name).replace(/[\x00]/g, "");
    if (!clean || clean === "." || clean === "..") {
        throw new Error("Invalid filename");
    }
    return clean;
}
export function validateCategory(category) {
    if (!CATEGORIES.includes(category)) {
        throw new Error(`Invalid category: ${category}`);
    }
}
export function getSharedAssetPath(category, filename) {
    validateCategory(category);
    const safe = sanitizeFilename(filename);
    const resolved = path.resolve(SHARED_DIR, category, safe);
    if (!resolved.startsWith(path.resolve(SHARED_DIR))) {
        throw new Error("Path traversal detected");
    }
    return resolved;
}
export async function ensureSharedDirs() {
    for (const cat of CATEGORIES) {
        await fs.mkdir(path.join(SHARED_DIR, cat), { recursive: true });
    }
}
export async function listSharedAssetsWithMeta() {
    const result = {};
    for (const cat of CATEGORIES) {
        const dir = path.join(SHARED_DIR, cat);
        try {
            const entries = await fs.readdir(dir, { withFileTypes: true });
            const files = [];
            for (const entry of entries) {
                if (!entry.isFile())
                    continue;
                try {
                    const stat = await fs.stat(path.join(dir, entry.name));
                    files.push({ name: entry.name, size: stat.size, mtime: stat.mtime.toISOString(), category: cat });
                }
                catch { /* skip unreadable files */ }
            }
            files.sort((a, b) => b.mtime.localeCompare(a.mtime));
            result[cat] = files;
        }
        catch {
            result[cat] = [];
        }
    }
    return result;
}
export async function listSharedAssets() {
    const meta = await listSharedAssetsWithMeta();
    const result = {};
    for (const [cat, files] of Object.entries(meta)) {
        result[cat] = files.map((f) => f.name);
    }
    return result;
}
export async function saveSharedAsset(category, filename, data) {
    const filePath = getSharedAssetPath(category, filename);
    await fs.writeFile(filePath, data);
    const stat = await fs.stat(filePath);
    return { name: sanitizeFilename(filename), size: stat.size, mtime: stat.mtime.toISOString(), category };
}
export async function deleteSharedAsset(category, filename) {
    const filePath = getSharedAssetPath(category, filename);
    await fs.unlink(filePath);
}
export async function moveSharedAsset(fromCat, toCat, filename) {
    const src = getSharedAssetPath(fromCat, filename);
    const dst = getSharedAssetPath(toCat, filename);
    try {
        await fs.access(dst);
        throw new Error("File already exists at destination");
    }
    catch (e) {
        if (e.message === "File already exists at destination")
            throw e;
    }
    await fs.rename(src, dst);
}
export { CATEGORIES, SHARED_DIR };
//# sourceMappingURL=shared-assets.js.map