/**
 * AssetManager — библиотека пользовательских картинок проекта.
 *
 * Зачем: даёт автору игры загрузить свои PNG/JPG и использовать их
 *   - как текстуру на гранях примитива (поле `textureAsset` в данных примитива);
 *   - как картинку в image-GUI (поле `imageAsset` у GUI-элемента).
 *
 * Как хранится: каждый ассет — { id, name, dataUrl }, где dataUrl —
 * base64-PNG. Библиотека сериализуется в scene.assets и едет в БД вместе
 * с проектом (своего файлового хранилища у Рублокс-веба пока нет, поэтому
 * картинки встроены в JSON — так же как аватары пользователей в нативе).
 *
 * Ограничения (чтобы JSON проекта не раздувался и не ломал автосейв):
 *   MAX_ASSETS   — не больше 24 картинок на проект;
 *   MAX_SIDE     — картинка ужимается до 512px по большей стороне;
 *   приводится к PNG через canvas — единый формат, отсекает EXIF и т.п.
 */

export const MAX_ASSETS = 24;
export const MAX_SIDE = 512;

let _idSeq = 1;

export class AssetManager {
    constructor() {
        // Map id → { id, name, dataUrl }
        this.assets = new Map();
    }

    /** Все ассеты массивом — для UI-панели. */
    list() {
        return [...this.assets.values()];
    }

    get(id) {
        return this.assets.get(id) || null;
    }

    /** dataURL по id — то, что отдаём в Babylon Texture / <img src>. */
    getDataUrl(id) {
        const a = this.assets.get(id);
        return a ? a.dataUrl : null;
    }

    count() {
        return this.assets.size;
    }

    /**
     * Загрузить картинку из File (input type=file).
     * Возвращает Promise<{ ok, id?, error? }>.
     * Картинка нормализуется: ужимается до MAX_SIDE, конвертится в PNG.
     */
    addFromFile(file) {
        return new Promise((resolve) => {
            if (this.assets.size >= MAX_ASSETS) {
                resolve({ ok: false, error: `Лимит ${MAX_ASSETS} картинок на проект` });
                return;
            }
            if (!file || !/^image\//.test(file.type)) {
                resolve({ ok: false, error: 'Это не картинка' });
                return;
            }
            const reader = new FileReader();
            reader.onerror = () => resolve({ ok: false, error: 'Не удалось прочитать файл' });
            reader.onload = () => {
                const img = new Image();
                img.onerror = () => resolve({ ok: false, error: 'Битая картинка' });
                img.onload = () => {
                    try {
                        const dataUrl = AssetManager._normalize(img);
                        const name = (file.name || 'картинка').replace(/\.[^.]+$/, '');
                        const id = this.add(name, dataUrl);
                        resolve({ ok: true, id });
                    } catch (e) {
                        resolve({ ok: false, error: 'Ошибка обработки картинки' });
                    }
                };
                img.src = reader.result;
            };
            reader.readAsDataURL(file);
        });
    }

    /** Добавить ассет с готовым dataUrl. Возвращает id. */
    add(name, dataUrl) {
        const id = `asset_${_idSeq++}`;
        this.assets.set(id, { id, name: name || 'картинка', dataUrl });
        return id;
    }

    rename(id, name) {
        const a = this.assets.get(id);
        if (a) a.name = name || a.name;
    }

    remove(id) {
        this.assets.delete(id);
    }

    /** Нормализация: ужать до MAX_SIDE, перерисовать в canvas → PNG dataURL. */
    static _normalize(img) {
        let w = img.naturalWidth || img.width;
        let h = img.naturalHeight || img.height;
        if (w <= 0 || h <= 0) throw new Error('zero size');
        if (w > MAX_SIDE || h > MAX_SIDE) {
            const k = MAX_SIDE / Math.max(w, h);
            w = Math.round(w * k);
            h = Math.round(h * k);
        }
        const canvas = document.createElement('canvas');
        canvas.width = w;
        canvas.height = h;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, w, h);
        return canvas.toDataURL('image/png');
    }

    // ============ STATE ============

    serialize() {
        return this.list().map(a => ({
            id: a.id, name: a.name, dataUrl: a.dataUrl,
        }));
    }

    load(data) {
        this.assets.clear();
        if (!Array.isArray(data)) return;
        let maxNum = 0;
        for (const a of data) {
            if (!a || typeof a.id !== 'string' || typeof a.dataUrl !== 'string') continue;
            this.assets.set(a.id, {
                id: a.id,
                name: typeof a.name === 'string' ? a.name : 'картинка',
                dataUrl: a.dataUrl,
            });
            const m = /^asset_(\d+)$/.exec(a.id);
            if (m) maxNum = Math.max(maxNum, Number(m[1]));
        }
        // Чтобы новые id не конфликтовали с загруженными.
        if (maxNum >= _idSeq) _idSeq = maxNum + 1;
    }

    dispose() {
        this.assets.clear();
    }
}
