import { SceneImporter } from './SceneImporter.js';

/**
 * @file OgmoImporter.ts
 * @description OGMO Editor Level Importer
 * PRO-1.3: Scene Format Interoperability
 *
 * OGMO Editor is a free, open-source 2D level editor.
 * Supports OGMO 3 format (JSON-based).
 *
 * File Types:
 * - .ogmo - Project file
 * - .json - Level file (usually named *.ogmo.json or just *.json)
 */
// ============================================================
// OGMO Importer
// ============================================================
class OgmoImporter extends SceneImporter {
    constructor() {
        super('ogmo');
        this.project = null;
        this.entityDefs = new Map();
        this.tilesetDefs = new Map();
        this.layerDefs = new Map();
    }
    canHandle(filePath) {
        const ext = filePath.substring(filePath.lastIndexOf('.')).toLowerCase();
        const name = filePath.toLowerCase();
        return ext === '.ogmo' || (ext === '.json' && name.includes('ogmo'));
    }
    async import(options) {
        const startTime = Date.now();
        this.options = options;
        this.clearMessages();
        const scenes = [];
        const assets = [];
        try {
            const content = await this.readFile(options.sourcePath);
            const data = JSON.parse(content);
            // Determine if this is a project file or level file
            if (this.isProjectFile(data)) {
                this.project = data;
                this.indexDefinitions();
                // Index assets from project
                for (const tileset of this.project.tilesets) {
                    assets.push({
                        id: this.generateId(),
                        name: tileset.name,
                        type: 'tileset',
                        path: tileset.path,
                        data: {
                            tileWidth: tileset.tileWidth,
                            tileHeight: tileset.tileHeight,
                            separationX: tileset.tileSeparationX,
                            separationY: tileset.tileSeparationY,
                            image: tileset.image,
                        },
                    });
                }
                // Import all level paths if specified
                if (this.project.levelPaths && options.resolveDependencies) {
                    for (const levelPath of this.project.levelPaths) {
                        try {
                            const levelContent = await this.readFile(this.resolvePath(options.sourcePath, levelPath));
                            const levelData = JSON.parse(levelContent);
                            const scene = this.convertLevelToScene(levelData, levelPath);
                            scenes.push(scene);
                        }
                        catch (error) {
                            this.addWarning('LEVEL_LOAD', `Failed to load level: ${levelPath}`, levelPath);
                        }
                    }
                }
            }
            else if (this.isLevelFile(data)) {
                const level = data;
                const scene = this.convertLevelToScene(level, options.sourcePath);
                scenes.push(scene);
            }
            else {
                this.addError('UNKNOWN_FORMAT', 'Unable to determine OGMO file type', options.sourcePath);
            }
        }
        catch (error) {
            this.addError('IMPORT_ERROR', `Failed to import: ${error}`, options.sourcePath, undefined, true);
        }
        return this.createResult(scenes, assets, startTime);
    }
    async parseFile(content, filePath) {
        const stringContent = typeof content === 'string' ? content : new TextDecoder().decode(content);
        try {
            const data = JSON.parse(stringContent);
            if (this.isLevelFile(data)) {
                return this.convertLevelToParsed(data);
            }
        }
        catch (_a) {
            return null;
        }
        return null;
    }
    async validate(sourcePath) {
        const errors = [];
        if (!this.canHandle(sourcePath)) {
            errors.push({
                code: 'INVALID_FORMAT',
                message: `File ${sourcePath} is not a valid OGMO file`,
                file: sourcePath,
                fatal: true,
            });
        }
        return errors;
    }
    // ----------------------------------------
    // Type Checks
    // ----------------------------------------
    isProjectFile(data) {
        const obj = data;
        return (typeof obj === 'object' &&
            obj !== null &&
            'ogmoVersion' in obj &&
            'layers' in obj &&
            'entities' in obj &&
            'tilesets' in obj);
    }
    isLevelFile(data) {
        const obj = data;
        return (typeof obj === 'object' &&
            obj !== null &&
            'ogmoVersion' in obj &&
            'width' in obj &&
            'height' in obj &&
            'layers' in obj &&
            !('entities' in obj && 'tilesets' in obj));
    }
    // ----------------------------------------
    // Index Definitions
    // ----------------------------------------
    indexDefinitions() {
        if (!this.project)
            return;
        this.entityDefs.clear();
        this.tilesetDefs.clear();
        this.layerDefs.clear();
        for (const entity of this.project.entities) {
            this.entityDefs.set(entity.exportID, entity);
            this.entityDefs.set(entity.name, entity);
        }
        for (const tileset of this.project.tilesets) {
            this.tilesetDefs.set(tileset.name, tileset);
        }
        for (const layer of this.project.layers) {
            this.layerDefs.set(layer.exportID, layer);
            this.layerDefs.set(layer.name, layer);
        }
    }
    // ----------------------------------------
    // Level Conversion
    // ----------------------------------------
    convertLevelToScene(level, sourcePath) {
        var _a;
        const name = this.extractFileName(sourcePath);
        const entities = [];
        let zIndex = 0;
        for (const layerInstance of level.layers) {
            const layerEntities = this.convertLayer(layerInstance, zIndex);
            entities.push(...layerEntities);
            zIndex++;
        }
        return {
            id: this.generateId(),
            name,
            entities,
            settings: {
                width: level.width,
                height: level.height,
                backgroundColor: ((_a = this.project) === null || _a === void 0 ? void 0 : _a.backgroundColor) || '#1a1a2e',
                offsetX: level.offsetX,
                offsetY: level.offsetY,
                ...level.values,
            },
        };
    }
    convertLevelToParsed(level) {
        var _a;
        const layers = [];
        const entities = [];
        for (let i = 0; i < level.layers.length; i++) {
            const layerInstance = level.layers[i];
            const parsedLayer = this.convertLayerToParsed(layerInstance, i);
            layers.push(parsedLayer);
            // Extract entities from entity layers
            if (layerInstance.entities) {
                for (const entityInstance of layerInstance.entities) {
                    entities.push(this.convertEntityToParsed(entityInstance, layerInstance.name));
                }
            }
        }
        return {
            name: 'OGMO Level',
            width: level.width,
            height: level.height,
            backgroundColor: ((_a = this.project) === null || _a === void 0 ? void 0 : _a.backgroundColor) || '#1a1a2e',
            layers,
            entities,
            properties: {
                offsetX: level.offsetX,
                offsetY: level.offsetY,
                ...level.values,
            },
        };
    }
    // ----------------------------------------
    // Layer Conversion
    // ----------------------------------------
    convertLayer(layerInstance, zIndex) {
        const entities = [];
        // Convert tile layer to tilemap entity
        if (layerInstance.data || layerInstance.data2D) {
            const tilemapEntity = this.convertTileLayer(layerInstance, zIndex);
            entities.push(tilemapEntity);
        }
        // Convert entity layer
        if (layerInstance.entities) {
            for (const entityInstance of layerInstance.entities) {
                entities.push(this.convertEntity(entityInstance, layerInstance.name, zIndex));
            }
        }
        // Convert decal layer
        if (layerInstance.decals) {
            for (const decal of layerInstance.decals) {
                entities.push(this.convertDecal(decal, layerInstance.name, zIndex));
            }
        }
        // Convert grid layer (usually collision)
        if (layerInstance.grid || layerInstance.grid2D) {
            const gridEntity = this.convertGridLayer(layerInstance, zIndex);
            entities.push(gridEntity);
        }
        return entities;
    }
    convertLayerToParsed(layerInstance, zIndex) {
        let type = 'object';
        let tileData;
        if (layerInstance.data) {
            type = 'tile';
            tileData = layerInstance.data;
        }
        else if (layerInstance.data2D) {
            type = 'tile';
            tileData = layerInstance.data2D.flat();
        }
        return {
            name: layerInstance.name,
            type,
            visible: true,
            opacity: 1,
            offsetX: layerInstance.offsetX,
            offsetY: layerInstance.offsetY,
            zIndex,
            tileData: tileData
                ? {
                    width: layerInstance.gridCellsX,
                    height: layerInstance.gridCellsY,
                    tiles: tileData,
                    tileWidth: layerInstance.gridCellWidth,
                    tileHeight: layerInstance.gridCellHeight,
                }
                : undefined,
            properties: {
                exportId: layerInstance._eid,
                tileset: layerInstance.tileset,
            },
        };
    }
    // ----------------------------------------
    // Tile Layer
    // ----------------------------------------
    convertTileLayer(layerInstance, zIndex) {
        let tileData = [];
        if (layerInstance.data) {
            tileData = layerInstance.data;
        }
        else if (layerInstance.data2D) {
            tileData = layerInstance.data2D.flat();
        }
        return {
            id: this.generateId(),
            name: layerInstance.name,
            components: [
                {
                    type: 'Transform',
                    data: {
                        position: { x: layerInstance.offsetX, y: layerInstance.offsetY },
                        rotation: 0,
                        scale: { x: 1, y: 1 },
                    },
                },
                {
                    type: 'Tilemap',
                    data: {
                        tileset: layerInstance.tileset,
                        width: layerInstance.gridCellsX,
                        height: layerInstance.gridCellsY,
                        tileWidth: layerInstance.gridCellWidth,
                        tileHeight: layerInstance.gridCellHeight,
                        data: tileData,
                        zIndex,
                    },
                },
            ],
            children: [],
            tags: ['tilemap', layerInstance.name],
            active: true,
        };
    }
    // ----------------------------------------
    // Entity Conversion
    // ----------------------------------------
    convertEntity(entityInstance, layer, zIndex) {
        const def = this.entityDefs.get(entityInstance._eid) || this.entityDefs.get(entityInstance.name);
        const components = [
            {
                type: 'Transform',
                data: {
                    position: { x: entityInstance.x, y: entityInstance.y },
                    rotation: entityInstance.rotation || 0,
                    scale: {
                        x: entityInstance.flippedX ? -1 : 1,
                        y: entityInstance.flippedY ? -1 : 1,
                    },
                },
            },
        ];
        // Add size component if entity has width/height
        if (entityInstance.width || entityInstance.height || (def === null || def === void 0 ? void 0 : def.size)) {
            components.push({
                type: 'Size',
                data: {
                    width: entityInstance.width || (def === null || def === void 0 ? void 0 : def.size.x) || 16,
                    height: entityInstance.height || (def === null || def === void 0 ? void 0 : def.size.y) || 16,
                },
            });
        }
        // Add sprite if texture is defined
        if (def === null || def === void 0 ? void 0 : def.texture) {
            components.push({
                type: 'Sprite',
                data: {
                    texture: def.texture,
                    textureRect: {
                        x: def.textureX || 0,
                        y: def.textureY || 0,
                        width: def.size.x,
                        height: def.size.y,
                    },
                    color: entityInstance.color || def.color,
                },
            });
        }
        // Add nodes if present (for paths, patrol routes, etc.)
        if (entityInstance.nodes && entityInstance.nodes.length > 0) {
            components.push({
                type: 'PathNodes',
                data: {
                    nodes: entityInstance.nodes,
                    display: (def === null || def === void 0 ? void 0 : def.nodeDisplay) || 'path',
                    closed: (def === null || def === void 0 ? void 0 : def.nodeDisplay) === 'circuit',
                },
            });
        }
        // Add custom values as properties component
        if (entityInstance.values) {
            components.push({
                type: 'Properties',
                data: entityInstance.values,
            });
        }
        return {
            id: entityInstance.id.toString(),
            name: entityInstance.name,
            components,
            children: [],
            tags: [layer, ...((def === null || def === void 0 ? void 0 : def.tags) || [])],
            active: true,
        };
    }
    convertEntityToParsed(entityInstance, layer) {
        const def = this.entityDefs.get(entityInstance._eid) || this.entityDefs.get(entityInstance.name);
        return {
            id: entityInstance.id.toString(),
            name: entityInstance.name,
            type: entityInstance.name,
            x: entityInstance.x,
            y: entityInstance.y,
            width: entityInstance.width || (def === null || def === void 0 ? void 0 : def.size.x) || 16,
            height: entityInstance.height || (def === null || def === void 0 ? void 0 : def.size.y) || 16,
            rotation: entityInstance.rotation || 0,
            scaleX: entityInstance.flippedX ? -1 : 1,
            scaleY: entityInstance.flippedY ? -1 : 1,
            visible: true,
            components: entityInstance.values
                ? [{ type: 'Properties', data: entityInstance.values }]
                : [],
            children: [],
            properties: {
                exportId: entityInstance._eid,
                layer,
                color: entityInstance.color,
                nodes: entityInstance.nodes,
                tags: def === null || def === void 0 ? void 0 : def.tags,
            },
        };
    }
    // ----------------------------------------
    // Decal Conversion
    // ----------------------------------------
    convertDecal(decal, layer, zIndex) {
        return {
            id: this.generateId(),
            name: this.extractFileName(decal.texture),
            components: [
                {
                    type: 'Transform',
                    data: {
                        position: { x: decal.x, y: decal.y },
                        rotation: decal.rotation || 0,
                        scale: { x: decal.scaleX || 1, y: decal.scaleY || 1 },
                    },
                },
                {
                    type: 'Sprite',
                    data: {
                        texture: decal.texture,
                        color: decal.color,
                        origin: decal.originX !== undefined ? { x: decal.originX, y: decal.originY || 0 } : undefined,
                        zIndex,
                    },
                },
            ],
            children: [],
            tags: ['decal', layer],
            active: true,
        };
    }
    // ----------------------------------------
    // Grid Layer (Collision)
    // ----------------------------------------
    convertGridLayer(layerInstance, zIndex) {
        let gridData = [];
        if (layerInstance.grid) {
            gridData = layerInstance.grid;
        }
        else if (layerInstance.grid2D) {
            gridData = layerInstance.grid2D.map((row) => row.join(''));
        }
        // Parse grid into collision data
        const collisionData = [];
        for (const row of gridData) {
            for (const char of row) {
                collisionData.push(char === '0' ? 0 : 1);
            }
        }
        return {
            id: this.generateId(),
            name: `${layerInstance.name}_collision`,
            components: [
                {
                    type: 'Transform',
                    data: {
                        position: { x: layerInstance.offsetX, y: layerInstance.offsetY },
                        rotation: 0,
                        scale: { x: 1, y: 1 },
                    },
                },
                {
                    type: 'CollisionGrid',
                    data: {
                        width: layerInstance.gridCellsX,
                        height: layerInstance.gridCellsY,
                        cellWidth: layerInstance.gridCellWidth,
                        cellHeight: layerInstance.gridCellHeight,
                        data: collisionData,
                        zIndex,
                    },
                },
            ],
            children: [],
            tags: ['collision', layerInstance.name],
            active: true,
        };
    }
    // ----------------------------------------
    // Utilities
    // ----------------------------------------
    async readFile(path) {
        var _a;
        if (typeof globalThis.process !== 'undefined' && ((_a = globalThis.process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
            const fs = await import('fs');
            return fs.readFileSync(path, 'utf-8');
        }
        else if (typeof fetch !== 'undefined') {
            const response = await fetch(path);
            return response.text();
        }
        throw new Error('Unable to read file in current environment');
    }
    resolvePath(basePath, relativePath) {
        const baseDir = basePath.substring(0, basePath.lastIndexOf('/') + 1);
        return baseDir + relativePath;
    }
    extractFileName(path) {
        const name = path.substring(path.lastIndexOf('/') + 1);
        const dotIndex = name.lastIndexOf('.');
        return dotIndex > 0 ? name.substring(0, dotIndex) : name;
    }
}
// ============================================================
// Factory Function
// ============================================================
function createOgmoImporter() {
    return new OgmoImporter();
}

export { OgmoImporter, createOgmoImporter };
//# sourceMappingURL=OgmoImporter.js.map
