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

/**
 * @file TiledMapImporter.ts
 * @description Import Tiled Map Editor files (.tmx, .tsx)
 * PRO-1.3: Scene Format Interoperability
 *
 * Supports:
 * - Tiled Map files (.tmx, .tmj)
 * - Tileset files (.tsx, .tsj)
 * - Template files (.tx, .tj)
 * - World files (.world)
 *
 * Features:
 * - Tile layers
 * - Object layers
 * - Image layers
 * - Group layers
 * - Animations
 * - Custom properties
 * - Collision shapes
 */
// ============================================================
// Tiled Map Importer
// ============================================================
class TiledMapImporter extends SceneImporter {
    constructor() {
        super('tiled');
        this.tilesets = new Map();
        this.tilesetsById = new Map();
    }
    async import(options) {
        const startTime = Date.now();
        this.options = options;
        this.clearMessages();
        this.tilesets.clear();
        this.tilesetsById.clear();
        const errors = await this.validate(options.sourcePath);
        if (errors.some((e) => e.fatal)) {
            return {
                ...this.createEmptyResult(),
                errors: errors,
            };
        }
        const scenes = [];
        const assets = [];
        try {
            const content = await this.readFile(options.sourcePath);
            const isJson = options.sourcePath.endsWith('.tmj') || options.sourcePath.endsWith('.json');
            const map = isJson ? this.parseJsonMap(content) : this.parseXmlMap(content);
            if (map) {
                // Parse external tilesets
                await this.loadExternalTilesets(map, options.sourcePath);
                const parsed = this.convertTiledMapToScene(map);
                const niceScene = this.convertParsedToNiceScene(parsed);
                scenes.push(niceScene);
                const extractedAssets = this.extractAssets(map);
                assets.push(...extractedAssets);
            }
        }
        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);
        const isJson = filePath.endsWith('.tmj') || filePath.endsWith('.json');
        const map = isJson ? this.parseJsonMap(stringContent) : this.parseXmlMap(stringContent);
        if (!map)
            return null;
        return this.convertTiledMapToScene(map);
    }
    async validate(sourcePath) {
        const errors = [];
        if (!this.canHandle(sourcePath)) {
            errors.push({
                code: 'INVALID_FORMAT',
                message: `File ${sourcePath} is not a valid Tiled file`,
                file: sourcePath,
                fatal: true,
            });
        }
        return errors;
    }
    // ----------------------------------------
    // Tiled Parsing
    // ----------------------------------------
    parseJsonMap(content) {
        try {
            const json = JSON.parse(content);
            return this.normalizeJsonMap(json);
        }
        catch (error) {
            this.addError('JSON_PARSE_ERROR', `Failed to parse JSON: ${error}`);
            return null;
        }
    }
    normalizeJsonMap(json) {
        var _a, _b;
        return {
            version: String(json.version || '1.0'),
            tiledVersion: String(json.tiledversion || ''),
            orientation: json.orientation || 'orthogonal',
            renderOrder: json.renderorder || 'right-down',
            width: Number(json.width) || 0,
            height: Number(json.height) || 0,
            tileWidth: Number(json.tilewidth) || 0,
            tileHeight: Number(json.tileheight) || 0,
            infinite: Boolean(json.infinite),
            backgroundColor: json.backgroundcolor ? String(json.backgroundcolor) : undefined,
            nextLayerId: Number(json.nextlayerid) || 0,
            nextObjectId: Number(json.nextobjectid) || 0,
            parallaxOriginX: json.parallaxoriginx ? Number(json.parallaxoriginx) : undefined,
            parallaxOriginY: json.parallaxoriginy ? Number(json.parallaxoriginy) : undefined,
            tilesets: ((_a = json.tilesets) === null || _a === void 0 ? void 0 : _a.map((ts) => this.normalizeJsonTileset(ts))) || [],
            layers: ((_b = json.layers) === null || _b === void 0 ? void 0 : _b.map((l) => this.normalizeJsonLayer(l))) || [],
            properties: this.normalizeProperties(json.properties),
            hexSideLength: json.hexsidelength ? Number(json.hexsidelength) : undefined,
            staggerAxis: json.staggeraxis,
            staggerIndex: json.staggerindex,
        };
    }
    normalizeJsonTileset(json) {
        const tileset = {
            firstGid: Number(json.firstgid) || 0,
            source: json.source ? String(json.source) : undefined,
            name: String(json.name || ''),
            tileWidth: Number(json.tilewidth) || 0,
            tileHeight: Number(json.tileheight) || 0,
            spacing: Number(json.spacing) || 0,
            margin: Number(json.margin) || 0,
            tileCount: Number(json.tilecount) || 0,
            columns: Number(json.columns) || 0,
            image: json.image ? String(json.image) : undefined,
            imageWidth: json.imagewidth ? Number(json.imagewidth) : undefined,
            imageHeight: json.imageheight ? Number(json.imageheight) : undefined,
            transparentColor: json.transparentcolor ? String(json.transparentcolor) : undefined,
            properties: this.normalizeProperties(json.properties),
        };
        if (json.tiles) {
            tileset.tiles = json.tiles.map((t) => this.normalizeJsonTile(t));
        }
        if (json.tileoffset) {
            const offset = json.tileoffset;
            tileset.tileOffset = { x: Number(offset.x) || 0, y: Number(offset.y) || 0 };
        }
        return tileset;
    }
    normalizeJsonTile(json) {
        var _a;
        const tile = {
            id: Number(json.id) || 0,
            type: json.type ? String(json.type) : undefined,
            properties: this.normalizeProperties(json.properties),
        };
        if (json.animation) {
            tile.animation = json.animation.map((f) => ({
                tileId: Number(f.tileid),
                duration: Number(f.duration),
            }));
        }
        if (json.objectgroup) {
            const og = json.objectgroup;
            tile.objectGroup = {
                drawOrder: String(og.draworder || 'index'),
                id: Number(og.id) || 0,
                name: String(og.name || ''),
                objects: ((_a = og.objects) === null || _a === void 0 ? void 0 : _a.map((o) => this.normalizeJsonObject(o))) || [],
            };
        }
        return tile;
    }
    normalizeJsonLayer(json) {
        var _a;
        const layer = {
            id: Number(json.id) || 0,
            name: String(json.name || ''),
            type: json.type || 'tilelayer',
            visible: json.visible !== false,
            opacity: json.opacity !== undefined ? Number(json.opacity) : 1,
            offsetX: Number(json.offsetx) || 0,
            offsetY: Number(json.offsety) || 0,
            parallaxX: json.parallaxx !== undefined ? Number(json.parallaxx) : 1,
            parallaxY: json.parallaxy !== undefined ? Number(json.parallaxy) : 1,
            tintColor: json.tintcolor ? String(json.tintcolor) : undefined,
            locked: json.locked ? Boolean(json.locked) : undefined,
            class: json.class ? String(json.class) : undefined,
            properties: this.normalizeProperties(json.properties),
        };
        // Tile layer specific
        if (json.type === 'tilelayer') {
            layer.width = Number(json.width) || 0;
            layer.height = Number(json.height) || 0;
            layer.data = json.data;
            layer.encoding = json.encoding;
            layer.compression = json.compression;
            if (json.chunks) {
                layer.chunks = json.chunks.map((c) => {
                    const chunk = c;
                    return {
                        x: Number(chunk.x),
                        y: Number(chunk.y),
                        width: Number(chunk.width),
                        height: Number(chunk.height),
                        data: chunk.data,
                    };
                });
            }
        }
        // Object layer specific
        if (json.type === 'objectgroup') {
            layer.objects =
                ((_a = json.objects) === null || _a === void 0 ? void 0 : _a.map((o) => this.normalizeJsonObject(o))) || [];
            layer.drawOrder = json.draworder || 'topdown';
            layer.color = json.color ? String(json.color) : undefined;
        }
        // Image layer specific
        if (json.type === 'imagelayer') {
            layer.image = json.image ? String(json.image) : undefined;
            layer.repeatX = json.repeatx ? Boolean(json.repeatx) : undefined;
            layer.repeatY = json.repeaty ? Boolean(json.repeaty) : undefined;
        }
        // Group layer specific
        if (json.type === 'group' && json.layers) {
            layer.layers = json.layers.map((l) => this.normalizeJsonLayer(l));
        }
        return layer;
    }
    normalizeJsonObject(json) {
        return {
            id: Number(json.id) || 0,
            name: String(json.name || ''),
            type: String(json.type || json.class || ''),
            x: Number(json.x) || 0,
            y: Number(json.y) || 0,
            width: Number(json.width) || 0,
            height: Number(json.height) || 0,
            rotation: Number(json.rotation) || 0,
            visible: json.visible !== false,
            gid: json.gid ? Number(json.gid) : undefined,
            template: json.template ? String(json.template) : undefined,
            point: json.point ? Boolean(json.point) : undefined,
            ellipse: json.ellipse ? Boolean(json.ellipse) : undefined,
            polygon: json.polygon,
            polyline: json.polyline,
            text: json.text,
            properties: this.normalizeProperties(json.properties),
        };
    }
    normalizeProperties(props) {
        if (!props)
            return undefined;
        return props.map((p) => {
            const prop = p;
            return {
                name: String(prop.name || ''),
                type: prop.type || 'string',
                value: prop.value,
                propertyType: prop.propertytype ? String(prop.propertytype) : undefined,
            };
        });
    }
    parseXmlMap(content) {
        try {
            const xml = parseXML(content);
            return this.normalizeXmlMap(xml);
        }
        catch (error) {
            this.addError('XML_PARSE_ERROR', `Failed to parse XML: ${error}`);
            return null;
        }
    }
    normalizeXmlMap(xml) {
        const map = {
            version: xml.attributes.version || '1.0',
            tiledVersion: xml.attributes.tiledversion || '',
            orientation: xml.attributes.orientation || 'orthogonal',
            renderOrder: xml.attributes.renderorder || 'right-down',
            width: parseInt(xml.attributes.width || '0', 10),
            height: parseInt(xml.attributes.height || '0', 10),
            tileWidth: parseInt(xml.attributes.tilewidth || '0', 10),
            tileHeight: parseInt(xml.attributes.tileheight || '0', 10),
            infinite: xml.attributes.infinite === '1',
            backgroundColor: xml.attributes.backgroundcolor,
            nextLayerId: parseInt(xml.attributes.nextlayerid || '0', 10),
            nextObjectId: parseInt(xml.attributes.nextobjectid || '0', 10),
            tilesets: [],
            layers: [],
            properties: this.parseXmlProperties(xml.children.find((c) => c.name === 'properties')),
        };
        // Parse tilesets
        for (const child of xml.children.filter((c) => c.name === 'tileset')) {
            map.tilesets.push(this.normalizeXmlTileset(child));
        }
        // Parse layers
        for (const child of xml.children) {
            if (['layer', 'objectgroup', 'imagelayer', 'group'].includes(child.name)) {
                map.layers.push(this.normalizeXmlLayer(child));
            }
        }
        return map;
    }
    normalizeXmlTileset(xml) {
        const tileset = {
            firstGid: parseInt(xml.attributes.firstgid || '0', 10),
            source: xml.attributes.source,
            name: xml.attributes.name || '',
            tileWidth: parseInt(xml.attributes.tilewidth || '0', 10),
            tileHeight: parseInt(xml.attributes.tileheight || '0', 10),
            spacing: parseInt(xml.attributes.spacing || '0', 10),
            margin: parseInt(xml.attributes.margin || '0', 10),
            tileCount: parseInt(xml.attributes.tilecount || '0', 10),
            columns: parseInt(xml.attributes.columns || '0', 10),
            properties: this.parseXmlProperties(xml.children.find((c) => c.name === 'properties')),
        };
        // Image
        const image = xml.children.find((c) => c.name === 'image');
        if (image) {
            tileset.image = image.attributes.source;
            tileset.imageWidth = parseInt(image.attributes.width || '0', 10);
            tileset.imageHeight = parseInt(image.attributes.height || '0', 10);
            tileset.transparentColor = image.attributes.trans;
        }
        // Tiles
        const tiles = xml.children.filter((c) => c.name === 'tile');
        if (tiles.length > 0) {
            tileset.tiles = tiles.map((t) => this.normalizeXmlTile(t));
        }
        // Tile offset
        const offset = xml.children.find((c) => c.name === 'tileoffset');
        if (offset) {
            tileset.tileOffset = {
                x: parseInt(offset.attributes.x || '0', 10),
                y: parseInt(offset.attributes.y || '0', 10),
            };
        }
        return tileset;
    }
    normalizeXmlTile(xml) {
        const tile = {
            id: parseInt(xml.attributes.id || '0', 10),
            type: xml.attributes.type,
            properties: this.parseXmlProperties(xml.children.find((c) => c.name === 'properties')),
        };
        // Animation
        const animation = xml.children.find((c) => c.name === 'animation');
        if (animation) {
            tile.animation = animation.children
                .filter((c) => c.name === 'frame')
                .map((f) => ({
                tileId: parseInt(f.attributes.tileid || '0', 10),
                duration: parseInt(f.attributes.duration || '0', 10),
            }));
        }
        // Collision (objectgroup)
        const objectGroup = xml.children.find((c) => c.name === 'objectgroup');
        if (objectGroup) {
            tile.objectGroup = {
                drawOrder: objectGroup.attributes.draworder || 'index',
                id: parseInt(objectGroup.attributes.id || '0', 10),
                name: objectGroup.attributes.name || '',
                objects: objectGroup.children
                    .filter((c) => c.name === 'object')
                    .map((o) => this.normalizeXmlObject(o)),
            };
        }
        return tile;
    }
    normalizeXmlLayer(xml) {
        const type = this.getLayerType(xml.name);
        const layer = {
            id: parseInt(xml.attributes.id || '0', 10),
            name: xml.attributes.name || '',
            type,
            visible: xml.attributes.visible !== '0',
            opacity: parseFloat(xml.attributes.opacity || '1'),
            offsetX: parseFloat(xml.attributes.offsetx || '0'),
            offsetY: parseFloat(xml.attributes.offsety || '0'),
            parallaxX: parseFloat(xml.attributes.parallaxx || '1'),
            parallaxY: parseFloat(xml.attributes.parallaxy || '1'),
            tintColor: xml.attributes.tintcolor,
            locked: xml.attributes.locked === '1',
            class: xml.attributes.class,
            properties: this.parseXmlProperties(xml.children.find((c) => c.name === 'properties')),
        };
        // Tile layer
        if (type === 'tilelayer') {
            layer.width = parseInt(xml.attributes.width || '0', 10);
            layer.height = parseInt(xml.attributes.height || '0', 10);
            const dataNode = xml.children.find((c) => c.name === 'data');
            if (dataNode) {
                layer.encoding = dataNode.attributes.encoding;
                layer.compression = dataNode.attributes.compression;
                if (layer.encoding === 'csv' || !layer.encoding) {
                    // CSV data
                    layer.data = dataNode.text.split(',').map((s) => parseInt(s.trim(), 10));
                }
                else if (layer.encoding === 'base64') {
                    // Base64 encoded - would need decompression for gzip/zlib
                    // For now, store as warning
                    this.addWarning('BASE64_DATA', 'Base64 encoded tile data requires decompression', xml.attributes.name);
                }
                // Chunks for infinite maps
                const chunks = dataNode.children.filter((c) => c.name === 'chunk');
                if (chunks.length > 0) {
                    layer.chunks = chunks.map((c) => ({
                        x: parseInt(c.attributes.x || '0', 10),
                        y: parseInt(c.attributes.y || '0', 10),
                        width: parseInt(c.attributes.width || '0', 10),
                        height: parseInt(c.attributes.height || '0', 10),
                        data: c.text.split(',').map((s) => parseInt(s.trim(), 10)),
                    }));
                }
            }
        }
        // Object layer
        if (type === 'objectgroup') {
            layer.objects = xml.children
                .filter((c) => c.name === 'object')
                .map((o) => this.normalizeXmlObject(o));
            layer.drawOrder = xml.attributes.draworder || 'topdown';
            layer.color = xml.attributes.color;
        }
        // Image layer
        if (type === 'imagelayer') {
            const image = xml.children.find((c) => c.name === 'image');
            if (image) {
                layer.image = image.attributes.source;
            }
            layer.repeatX = xml.attributes.repeatx === '1';
            layer.repeatY = xml.attributes.repeaty === '1';
        }
        // Group layer
        if (type === 'group') {
            layer.layers = [];
            for (const child of xml.children) {
                if (['layer', 'objectgroup', 'imagelayer', 'group'].includes(child.name)) {
                    layer.layers.push(this.normalizeXmlLayer(child));
                }
            }
        }
        return layer;
    }
    normalizeXmlObject(xml) {
        const obj = {
            id: parseInt(xml.attributes.id || '0', 10),
            name: xml.attributes.name || '',
            type: xml.attributes.type || xml.attributes.class || '',
            x: parseFloat(xml.attributes.x || '0'),
            y: parseFloat(xml.attributes.y || '0'),
            width: parseFloat(xml.attributes.width || '0'),
            height: parseFloat(xml.attributes.height || '0'),
            rotation: parseFloat(xml.attributes.rotation || '0'),
            visible: xml.attributes.visible !== '0',
            gid: xml.attributes.gid ? parseInt(xml.attributes.gid, 10) : undefined,
            template: xml.attributes.template,
            properties: this.parseXmlProperties(xml.children.find((c) => c.name === 'properties')),
        };
        // Point
        if (xml.children.some((c) => c.name === 'point')) {
            obj.point = true;
        }
        // Ellipse
        if (xml.children.some((c) => c.name === 'ellipse')) {
            obj.ellipse = true;
        }
        // Polygon
        const polygon = xml.children.find((c) => c.name === 'polygon');
        if (polygon && polygon.attributes.points) {
            obj.polygon = this.parsePoints(polygon.attributes.points);
        }
        // Polyline
        const polyline = xml.children.find((c) => c.name === 'polyline');
        if (polyline && polyline.attributes.points) {
            obj.polyline = this.parsePoints(polyline.attributes.points);
        }
        // Text
        const text = xml.children.find((c) => c.name === 'text');
        if (text) {
            obj.text = {
                text: text.text || '',
                fontFamily: text.attributes.fontfamily || 'sans-serif',
                pixelSize: parseInt(text.attributes.pixelsize || '16', 10),
                wrap: text.attributes.wrap === '1',
                color: text.attributes.color || '#000000',
                bold: text.attributes.bold === '1',
                italic: text.attributes.italic === '1',
                underline: text.attributes.underline === '1',
                strikeout: text.attributes.strikeout === '1',
                kerning: text.attributes.kerning !== '0',
                halign: text.attributes.halign || 'left',
                valign: text.attributes.valign || 'top',
            };
        }
        return obj;
    }
    parseXmlProperties(xml) {
        if (!xml)
            return undefined;
        return xml.children
            .filter((c) => c.name === 'property')
            .map((p) => ({
            name: p.attributes.name || '',
            type: p.attributes.type || 'string',
            value: this.parsePropertyValue(p.attributes.value || p.text, p.attributes.type),
            propertyType: p.attributes.propertytype,
        }));
    }
    parsePropertyValue(value, type) {
        switch (type) {
            case 'int':
                return parseInt(value, 10);
            case 'float':
                return parseFloat(value);
            case 'bool':
                return value === 'true';
            default:
                return value;
        }
    }
    parsePoints(pointsStr) {
        return pointsStr.split(' ').map((p) => {
            const [x, y] = p.split(',').map((v) => parseFloat(v));
            return { x, y };
        });
    }
    getLayerType(xmlName) {
        switch (xmlName) {
            case 'layer':
                return 'tilelayer';
            case 'objectgroup':
                return 'objectgroup';
            case 'imagelayer':
                return 'imagelayer';
            case 'group':
                return 'group';
            default:
                return 'tilelayer';
        }
    }
    async loadExternalTilesets(map, mapPath) {
        const basePath = mapPath.substring(0, mapPath.lastIndexOf('/') + 1);
        for (const tileset of map.tilesets) {
            if (tileset.source) {
                try {
                    const tilesetPath = basePath + tileset.source;
                    const content = await this.readFile(tilesetPath);
                    const isJson = tileset.source.endsWith('.tsj') || tileset.source.endsWith('.json');
                    let externalTileset;
                    if (isJson) {
                        const json = JSON.parse(content);
                        externalTileset = this.normalizeJsonTileset(json);
                    }
                    else {
                        const xml = parseXML(content);
                        const tilesetNode = xml.name === 'tileset' ? xml : xml.children.find((c) => c.name === 'tileset');
                        if (tilesetNode) {
                            externalTileset = this.normalizeXmlTileset(tilesetNode);
                        }
                        else {
                            continue;
                        }
                    }
                    // Merge external tileset data
                    Object.assign(tileset, externalTileset, { firstGid: tileset.firstGid });
                }
                catch (error) {
                    this.addWarning('TILESET_LOAD_ERROR', `Failed to load external tileset: ${tileset.source}`, tileset.source);
                }
            }
            // Index tileset by first gid
            this.tilesets.set(tileset.name, tileset);
            this.tilesetsById.set(tileset.firstGid, tileset);
        }
    }
    // ----------------------------------------
    // Conversion
    // ----------------------------------------
    convertTiledMapToScene(map) {
        const layers = [];
        const entities = [];
        let zIndex = 0;
        this.processLayers(map.layers, layers, entities, zIndex);
        return {
            name: 'TiledMap',
            width: map.width * map.tileWidth,
            height: map.height * map.tileHeight,
            backgroundColor: map.backgroundColor || '#000000',
            layers,
            entities,
            properties: {
                orientation: map.orientation,
                renderOrder: map.renderOrder,
                tileWidth: map.tileWidth,
                tileHeight: map.tileHeight,
                infinite: map.infinite,
                ...this.convertProperties(map.properties),
            },
        };
    }
    processLayers(layers, outLayers, outEntities, zIndex) {
        for (const layer of layers) {
            if (layer.type === 'group' && layer.layers) {
                zIndex = this.processLayers(layer.layers, outLayers, outEntities, zIndex);
            }
            else {
                outLayers.push(this.convertLayer(layer, zIndex));
                // Extract objects as entities
                if (layer.type === 'objectgroup' && layer.objects) {
                    for (const obj of layer.objects) {
                        outEntities.push(this.convertObject(obj, layer.name, zIndex));
                    }
                }
                zIndex++;
            }
        }
        return zIndex;
    }
    convertLayer(layer, zIndex) {
        const parsedLayer = {
            name: layer.name,
            type: this.mapLayerType(layer.type),
            visible: layer.visible,
            opacity: layer.opacity,
            offsetX: layer.offsetX,
            offsetY: layer.offsetY,
            parallaxX: layer.parallaxX,
            parallaxY: layer.parallaxY,
            zIndex,
            properties: this.convertProperties(layer.properties),
        };
        // Tile data
        if (layer.type === 'tilelayer' && layer.data) {
            parsedLayer.data = {
                width: layer.width || 0,
                height: layer.height || 0,
                tileWidth: 0, // Will be set from tileset
                tileHeight: 0,
                tiles: layer.data,
            };
        }
        return parsedLayer;
    }
    mapLayerType(type) {
        switch (type) {
            case 'tilelayer':
                return 'tile';
            case 'objectgroup':
                return 'object';
            case 'imagelayer':
                return 'image';
            case 'group':
                return 'group';
            default:
                return 'object';
        }
    }
    convertObject(obj, layerName, zIndex) {
        const components = [];
        // Determine shape type
        if (obj.polygon) {
            components.push({
                type: 'PolygonCollider',
                data: {
                    points: obj.polygon,
                    isTrigger: false,
                },
            });
        }
        else if (obj.polyline) {
            components.push({
                type: 'EdgeCollider',
                data: {
                    points: obj.polyline,
                },
            });
        }
        else if (obj.ellipse) {
            components.push({
                type: 'CircleCollider',
                data: {
                    radius: Math.max(obj.width, obj.height) / 2,
                    isTrigger: false,
                },
            });
        }
        else if (obj.point) {
            components.push({
                type: 'Point',
                data: {},
            });
        }
        else if (obj.text) {
            components.push({
                type: 'Text',
                data: {
                    text: obj.text.text,
                    fontFamily: obj.text.fontFamily,
                    fontSize: obj.text.pixelSize,
                    color: obj.text.color,
                    bold: obj.text.bold,
                    italic: obj.text.italic,
                    align: obj.text.halign,
                    valign: obj.text.valign,
                    wrap: obj.text.wrap,
                },
            });
        }
        else if (obj.gid) {
            // Tile object
            const tileset = this.findTilesetForGid(obj.gid);
            if (tileset) {
                const localId = obj.gid - tileset.firstGid;
                components.push({
                    type: 'Sprite',
                    data: {
                        tileset: tileset.name,
                        tileId: localId,
                        width: obj.width,
                        height: obj.height,
                    },
                });
            }
        }
        else {
            // Rectangle
            components.push({
                type: 'BoxCollider',
                data: {
                    width: obj.width,
                    height: obj.height,
                    isTrigger: false,
                },
            });
        }
        return {
            id: obj.id.toString(),
            name: obj.name || `Object_${obj.id}`,
            type: obj.type || 'TiledObject',
            x: obj.x,
            y: obj.y,
            width: obj.width,
            height: obj.height,
            rotation: obj.rotation,
            scaleX: 1,
            scaleY: 1,
            visible: obj.visible,
            components,
            children: [],
            properties: {
                layer: layerName,
                zIndex,
                ...this.convertProperties(obj.properties),
            },
        };
    }
    findTilesetForGid(gid) {
        // Clear flip flags
        const tileId = gid & 0x0fffffff;
        let result = null;
        let maxFirstGid = 0;
        for (const [_, tileset] of this.tilesetsById) {
            if (tileset.firstGid <= tileId && tileset.firstGid > maxFirstGid) {
                maxFirstGid = tileset.firstGid;
                result = tileset;
            }
        }
        return result;
    }
    convertProperties(props) {
        if (!props)
            return {};
        const result = {};
        for (const prop of props) {
            result[prop.name] = prop.value;
        }
        return result;
    }
    extractAssets(map) {
        var _a;
        const assets = [];
        // Extract tileset images
        for (const tileset of map.tilesets) {
            if (tileset.image) {
                assets.push({
                    id: this.generateId(),
                    name: tileset.name,
                    type: 'tileset',
                    path: tileset.image,
                    data: {
                        tileWidth: tileset.tileWidth,
                        tileHeight: tileset.tileHeight,
                        tileCount: tileset.tileCount,
                        columns: tileset.columns,
                        margin: tileset.margin,
                        spacing: tileset.spacing,
                        firstGid: tileset.firstGid,
                        tiles: (_a = tileset.tiles) === null || _a === void 0 ? void 0 : _a.map((t) => {
                            var _a;
                            return ({
                                id: t.id,
                                type: t.type,
                                animation: t.animation,
                                collision: (_a = t.objectGroup) === null || _a === void 0 ? void 0 : _a.objects,
                            });
                        }),
                    },
                });
            }
        }
        // Extract image layer images
        for (const layer of this.flattenLayers(map.layers)) {
            if (layer.type === 'imagelayer' && layer.image) {
                assets.push({
                    id: this.generateId(),
                    name: layer.name + '_image',
                    type: 'texture',
                    path: layer.image,
                    data: {
                        repeatX: layer.repeatX,
                        repeatY: layer.repeatY,
                    },
                });
            }
        }
        return assets;
    }
    flattenLayers(layers) {
        const result = [];
        for (const layer of layers) {
            result.push(layer);
            if (layer.type === 'group' && layer.layers) {
                result.push(...this.flattenLayers(layer.layers));
            }
        }
        return result;
    }
    // ----------------------------------------
    // Helper Methods
    // ----------------------------------------
    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');
    }
}

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