/**
 * GlbLibrary — библиотека импортированных пользователем 3D-моделей .glb
 * (Фаза 5.8).
 *
 * Зачем: автор может загрузить свою glTF/GLB-модель и ставить её в сцену
 * как обычную модель — через палитру или scene.spawn('glb:<id>').
 *
 * Как хранится: каждая модель — { id, name, dataUrl }, dataUrl — base64
 * GLB. Сериализуется в scene.glbModels, едет в БД с проектом (своего
 * файлового хранилища у Рублокс-веба нет — как звуки/картинки).
 *
 * Ограничения (GLB в base64 сильно раздувает JSON проекта):
 *   MAX_GLB   — не больше 6 моделей на проект;
 *   MAX_BYTES — не больше 4 МБ на модель.
 */

export const MAX_GLB = 6;
export const MAX_GLB_BYTES = 4 * 1024 * 1024;

let _glbIdSeq = 1;

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

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

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

    /** dataURL по id — base64 GLB для SceneLoader. */
    getDataUrl(id) {
        const m = this.models.get(id);
        return m ? m.dataUrl : null;
    }

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

    /**
     * Загрузить .glb из File (input type=file).
     * Возвращает Promise<{ ok, id?, error? }>.
     */
    addFromFile(file) {
        return new Promise((resolve) => {
            if (this.models.size >= MAX_GLB) {
                resolve({ ok: false, error: `Лимит ${MAX_GLB} моделей на проект` });
                return;
            }
            const name = (file && file.name) || '';
            if (!/\.(glb|gltf)$/i.test(name)) {
                resolve({ ok: false, error: 'Нужен файл .glb или .gltf' });
                return;
            }
            if (file.size > MAX_GLB_BYTES) {
                resolve({
                    ok: false,
                    error: `Модель слишком большая (макс ${Math.round(MAX_GLB_BYTES / 1024 / 1024)} МБ)`,
                });
                return;
            }
            const reader = new FileReader();
            reader.onerror = () => resolve({ ok: false, error: 'Не удалось прочитать файл' });
            reader.onload = () => {
                const dataUrl = reader.result;
                if (typeof dataUrl !== 'string') {
                    resolve({ ok: false, error: 'Битый файл' });
                    return;
                }
                if (dataUrl.length > MAX_GLB_BYTES * 1.4) {
                    resolve({ ok: false, error: 'Модель слишком большая' });
                    return;
                }
                const cleanName = name.replace(/\.[^.]+$/, '');
                const id = this.add(cleanName, dataUrl);
                resolve({ ok: true, id });
            };
            reader.readAsDataURL(file);
        });
    }

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

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

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

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

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

    load(data) {
        this.models.clear();
        if (!Array.isArray(data)) return;
        let maxNum = 0;
        for (const m of data) {
            if (!m || typeof m.id !== 'string' || typeof m.dataUrl !== 'string') continue;
            this.models.set(m.id, {
                id: m.id,
                name: typeof m.name === 'string' ? m.name : 'модель',
                dataUrl: m.dataUrl,
            });
            const mt = /^glb_(\d+)$/.exec(m.id);
            if (mt) maxNum = Math.max(maxNum, Number(mt[1]));
        }
        if (maxNum >= _glbIdSeq) _glbIdSeq = maxNum + 1;
    }

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