import { EventBus } from '../core/EventBus.js';

/* ────────────────────────────────────────────────────────────────
   Asset Manager — Asset registry, import, thumbnails
──────────────────────────────────────────────────────────────── */
/* ── Asset Manager ────────────────────────────────────────────── */
class AssetManager {
    constructor() {
        this.events = new EventBus();
        this.assets = new Map();
        this.blobStore = new Map();
        this.objectUrls = new Map();
    }
    /* ── Registration ───────────────────────────────────────────── */
    register(meta, blob) {
        this.assets.set(meta.id, meta);
        if (blob)
            this.blobStore.set(meta.id, blob);
        this.events.emit('asset:added', meta);
    }
    remove(id) {
        this.revokeObjectUrl(id);
        this.assets.delete(id);
        this.blobStore.delete(id);
        this.events.emit('asset:removed', id);
    }
    get(id) {
        return this.assets.get(id);
    }
    getBlob(id) {
        return this.blobStore.get(id);
    }
    getAll() {
        return Array.from(this.assets.values());
    }
    /* ── Querying ───────────────────────────────────────────────── */
    getByType(type) {
        return this.getAll().filter(a => a.type === type);
    }
    search(query) {
        const q = query.toLowerCase();
        return this.getAll().filter(a => a.name.toLowerCase().includes(q) ||
            a.tags.some(t => t.toLowerCase().includes(q)));
    }
    /* ── Object URLs ────────────────────────────────────────────── */
    getObjectUrl(id) {
        const existing = this.objectUrls.get(id);
        if (existing)
            return existing;
        const blob = this.blobStore.get(id);
        if (!blob)
            return null;
        const url = URL.createObjectURL(blob);
        this.objectUrls.set(id, url);
        return url;
    }
    revokeObjectUrl(id) {
        const url = this.objectUrls.get(id);
        if (url) {
            URL.revokeObjectURL(url);
            this.objectUrls.delete(id);
        }
    }
    /* ── Import from File ───────────────────────────────────────── */
    async importFile(file, folder = '/') {
        const type = this.inferType(file.type, file.name);
        const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
        const now = Date.now();
        const meta = {
            id,
            name: file.name,
            type,
            path: `${folder}${file.name}`,
            size: file.size,
            mimeType: file.type,
            tags: [],
            createdAt: now,
            modifiedAt: now,
        };
        // Generate thumbnail for images
        if (type === 'sprite' || type === 'spritesheet') {
            meta.thumbnailDataUrl = await this.generateImageThumbnail(file);
        }
        this.register(meta, file);
        return meta;
    }
    async importFiles(files, folder = '/') {
        const result = [];
        for (const file of Array.from(files)) {
            result.push(await this.importFile(file, folder));
        }
        return result;
    }
    inferType(mimeType, fileName) {
        if (mimeType.startsWith('image/'))
            return 'sprite';
        if (mimeType.startsWith('audio/'))
            return 'audio';
        if (mimeType === 'application/json' || fileName.endsWith('.ndg'))
            return 'scene';
        if (fileName.endsWith('.prefab') || fileName.endsWith('.prefab.json'))
            return 'prefab';
        return 'script';
    }
    generateImageThumbnail(file, maxSize = 64) {
        return new Promise((resolve) => {
            const img = new Image();
            const url = URL.createObjectURL(file);
            img.onload = () => {
                const scale = Math.min(maxSize / img.width, maxSize / img.height, 1);
                const canvas = document.createElement('canvas');
                canvas.width = Math.round(img.width * scale);
                canvas.height = Math.round(img.height * scale);
                const ctx2 = canvas.getContext('2d');
                if (ctx2) {
                    ctx2.imageSmoothingEnabled = false;
                    ctx2.drawImage(img, 0, 0, canvas.width, canvas.height);
                }
                URL.revokeObjectURL(url);
                resolve(canvas.toDataURL('image/png'));
            };
            img.onerror = () => {
                URL.revokeObjectURL(url);
                resolve('');
            };
            img.src = url;
        });
    }
    /* ── Manifest ───────────────────────────────────────────────── */
    toManifest() {
        const assets = this.getAll().map(a => ({
            id: a.id,
            name: a.name,
            type: a.type,
            path: a.path,
        }));
        return { assets };
    }
    /* ── Folder tree ────────────────────────────────────────────── */
    getFolderTree() {
        const root = { name: 'Assets', path: '/', children: [] };
        const folderMap = new Map();
        folderMap.set('/', root);
        for (const asset of this.getAll()) {
            const parts = asset.path.split('/').filter(Boolean);
            parts.pop();
            let currentPath = '/';
            let currentFolder = root;
            for (const part of parts) {
                currentPath += part + '/';
                let folder = folderMap.get(currentPath);
                if (!folder) {
                    folder = { name: part, path: currentPath, children: [] };
                    folderMap.set(currentPath, folder);
                    currentFolder.children.push(folder);
                }
                currentFolder = folder;
            }
            currentFolder.children.push(asset);
        }
        return root;
    }
    /* ── Cleanup ────────────────────────────────────────────────── */
    clear() {
        for (const id of this.objectUrls.keys()) {
            this.revokeObjectUrl(id);
        }
        this.assets.clear();
        this.blobStore.clear();
        this.events.emit('asset:cleared', null);
    }
    /** Get assets not referenced by any entity in the given world. */
    findUnused(world) {
        const usedIds = new Set();
        for (const e of world.allEntities()) {
            const sprite = world.getComponent(e.id, 'Sprite');
            if (sprite === null || sprite === void 0 ? void 0 : sprite.assetId)
                usedIds.add(sprite.assetId);
            const audio = world.getComponent(e.id, 'AudioSource');
            if (audio === null || audio === void 0 ? void 0 : audio.soundId)
                usedIds.add(audio.soundId);
        }
        return this.getAll().filter(a => !usedIds.has(a.id));
    }
}

export { AssetManager };
//# sourceMappingURL=AssetManager.js.map
