'use strict';

var SceneImporter = require('./SceneImporter.js');

/**
 * @file DragonBonesImporter.ts
 * @description DragonBones Skeletal Animation Importer
 * PRO-1.3: Scene Format Interoperability
 *
 * DragonBones is a free, open-source 2D skeletal animation tool.
 *
 * File Types:
 * - *_ske.json - Skeleton data
 * - *_tex.json - Texture atlas data
 * - *_tex.png - Texture image
 */
// ============================================================
// DragonBones Importer
// ============================================================
class DragonBonesImporter extends SceneImporter.SceneImporter {
    constructor() {
        super('dragonbones');
        this.textureAtlas = null;
    }
    canHandle(filePath) {
        const name = filePath.toLowerCase();
        return name.endsWith('_ske.json') || name.endsWith('_tex.json') || name.endsWith('.dbbin');
    }
    async import(options) {
        const startTime = Date.now();
        this.options = options;
        this.clearMessages();
        const scenes = [];
        const assets = [];
        try {
            const fileName = options.sourcePath.toLowerCase();
            const content = await this.readFile(options.sourcePath);
            if (fileName.endsWith('_tex.json')) {
                // Parse texture atlas
                this.textureAtlas = JSON.parse(content);
                // Create texture asset
                assets.push({
                    id: this.generateId(),
                    name: this.textureAtlas.name,
                    type: 'texture',
                    path: this.textureAtlas.imagePath,
                    data: {
                        width: this.textureAtlas.width,
                        height: this.textureAtlas.height,
                    },
                });
                // Create subtexture assets
                for (const subTex of this.textureAtlas.SubTexture) {
                    assets.push({
                        id: this.generateId(),
                        name: subTex.name,
                        type: 'texture',
                        path: this.textureAtlas.imagePath,
                        data: {
                            frame: { x: subTex.x, y: subTex.y, width: subTex.width, height: subTex.height },
                            sourceSize: subTex.frameWidth && subTex.frameHeight
                                ? { width: subTex.frameWidth, height: subTex.frameHeight }
                                : undefined,
                            offset: subTex.frameX !== undefined
                                ? { x: subTex.frameX, y: subTex.frameY || 0 }
                                : undefined,
                        },
                    });
                }
            }
            else if (fileName.endsWith('_ske.json')) {
                // Parse skeleton data
                const skeleton = JSON.parse(content);
                // Try to load texture atlas
                if (options.resolveDependencies) {
                    const texPath = options.sourcePath.replace('_ske.json', '_tex.json');
                    try {
                        const texContent = await this.readFile(texPath);
                        this.textureAtlas = JSON.parse(texContent);
                    }
                    catch (_a) {
                        this.addWarning('TEX_NOT_FOUND', 'Texture atlas not found', texPath);
                    }
                }
                // Convert each armature to a scene
                for (const armature of skeleton.armature) {
                    const scene = this.convertArmatureToScene(armature, skeleton);
                    scenes.push(scene);
                    // Extract display assets
                    for (const skin of armature.skin) {
                        for (const slot of skin.slot) {
                            for (const display of slot.display) {
                                if (display.type === 'image' || !display.type) {
                                    const imageDisplay = display;
                                    assets.push({
                                        id: this.generateId(),
                                        name: imageDisplay.path || imageDisplay.name,
                                        type: 'texture',
                                        path: imageDisplay.path || imageDisplay.name,
                                        data: {
                                            pivot: imageDisplay.pivot,
                                        },
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }
        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 {
            if (filePath.toLowerCase().endsWith('_tex.json')) {
                return null; // Texture files don't produce scenes
            }
            const skeleton = JSON.parse(stringContent);
            if (skeleton.armature && skeleton.armature.length > 0) {
                return this.convertArmatureToParsed(skeleton.armature[0], skeleton);
            }
        }
        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 DragonBones file`,
                file: sourcePath,
                fatal: true,
            });
        }
        return errors;
    }
    // ----------------------------------------
    // Armature Conversion
    // ----------------------------------------
    convertArmatureToScene(armature, skeleton) {
        var _a, _b, _c;
        const entities = [];
        // Create root entity
        const rootEntity = {
            id: this.generateId(),
            name: armature.name,
            components: [
                {
                    type: 'Transform',
                    data: {
                        position: { x: 0, y: 0 },
                        rotation: 0,
                        scale: { x: 1, y: 1 },
                    },
                },
                {
                    type: 'DragonBonesArmature',
                    data: {
                        version: skeleton.version,
                        frameRate: armature.frameRate || skeleton.frameRate,
                        aabb: armature.aabb,
                        skins: armature.skin.map((s) => s.name),
                        animations: armature.animation.map((a) => a.name),
                    },
                },
            ],
            children: [],
            tags: ['dragonbones', 'armature'],
            active: true,
        };
        // Create bone hierarchy
        rootEntity.children = this.createBoneHierarchy(armature.bone);
        // Add slots
        for (const slot of armature.slot) {
            this.addSlotToEntity(rootEntity, slot, armature);
        }
        // Add IK constraints
        if (armature.ik) {
            for (const ik of armature.ik) {
                rootEntity.components.push({
                    type: 'IKConstraint',
                    data: {
                        name: ik.name,
                        bone: ik.bone,
                        target: ik.target,
                        chain: (_a = ik.chain) !== null && _a !== void 0 ? _a : 0,
                        bendPositive: (_b = ik.bendPositive) !== null && _b !== void 0 ? _b : true,
                        weight: (_c = ik.weight) !== null && _c !== void 0 ? _c : 1,
                    },
                });
            }
        }
        // Add animations
        for (const anim of armature.animation) {
            rootEntity.components.push({
                type: 'Animation',
                data: this.convertAnimation(anim, armature.frameRate || skeleton.frameRate),
            });
        }
        entities.push(rootEntity);
        return {
            id: this.generateId(),
            name: armature.name,
            entities,
            settings: {
                width: armature.aabb.width,
                height: armature.aabb.height,
                backgroundColor: '#1a1a2e',
                frameRate: armature.frameRate || skeleton.frameRate,
            },
        };
    }
    convertArmatureToParsed(armature, skeleton) {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const entities = [];
        // Create bone entities
        for (const bone of armature.bone) {
            entities.push({
                id: bone.name,
                name: bone.name,
                type: 'Bone',
                x: ((_a = bone.transform) === null || _a === void 0 ? void 0 : _a.x) || 0,
                y: ((_b = bone.transform) === null || _b === void 0 ? void 0 : _b.y) || 0,
                width: bone.length || 0,
                height: 4,
                rotation: ((_c = bone.transform) === null || _c === void 0 ? void 0 : _c.skX) || 0,
                scaleX: (_e = (_d = bone.transform) === null || _d === void 0 ? void 0 : _d.scX) !== null && _e !== void 0 ? _e : 1,
                scaleY: (_g = (_f = bone.transform) === null || _f === void 0 ? void 0 : _f.scY) !== null && _g !== void 0 ? _g : 1,
                visible: true,
                components: [],
                children: [],
                properties: {
                    parent: bone.parent,
                    length: bone.length,
                    skewY: (_h = bone.transform) === null || _h === void 0 ? void 0 : _h.skY,
                },
            });
        }
        // Create slot entities
        for (const slot of armature.slot) {
            entities.push({
                id: slot.name,
                name: slot.name,
                type: 'Slot',
                x: 0,
                y: 0,
                width: 32,
                height: 32,
                rotation: 0,
                scaleX: 1,
                scaleY: 1,
                visible: true,
                components: [],
                children: [],
                properties: {
                    bone: slot.parent,
                    displayIndex: slot.displayIndex,
                    blendMode: slot.blendMode,
                    color: slot.color,
                },
            });
        }
        return {
            name: armature.name,
            width: armature.aabb.width,
            height: armature.aabb.height,
            backgroundColor: '#1a1a2e',
            layers: [
                {
                    name: 'Armature',
                    type: 'object',
                    visible: true,
                    opacity: 1,
                    offsetX: 0,
                    offsetY: 0,
                    zIndex: 0,
                    properties: {},
                },
            ],
            entities,
            properties: {
                version: skeleton.version,
                frameRate: armature.frameRate || skeleton.frameRate,
                animations: armature.animation.map((a) => a.name),
                skins: armature.skin.map((s) => s.name),
            },
        };
    }
    // ----------------------------------------
    // Bone Hierarchy
    // ----------------------------------------
    createBoneHierarchy(bones) {
        var _a, _b, _c, _d, _e;
        const boneMap = new Map();
        const rootBones = [];
        // Create all bone entities first
        for (const bone of bones) {
            const transform = bone.transform || {};
            const entity = {
                id: bone.name,
                name: bone.name,
                components: [
                    {
                        type: 'Transform',
                        data: {
                            position: { x: transform.x || 0, y: transform.y || 0 },
                            rotation: transform.skX || 0,
                            scale: { x: (_a = transform.scX) !== null && _a !== void 0 ? _a : 1, y: (_b = transform.scY) !== null && _b !== void 0 ? _b : 1 },
                        },
                    },
                    {
                        type: 'Bone',
                        data: {
                            length: bone.length || 0,
                            skewY: transform.skY || 0,
                            inheritTranslation: (_c = bone.inheritTranslation) !== null && _c !== void 0 ? _c : true,
                            inheritRotation: (_d = bone.inheritRotation) !== null && _d !== void 0 ? _d : true,
                            inheritScale: (_e = bone.inheritScale) !== null && _e !== void 0 ? _e : true,
                        },
                    },
                ],
                children: [],
                tags: ['bone'],
                active: true,
            };
            boneMap.set(bone.name, entity);
        }
        // Build hierarchy
        for (const bone of bones) {
            const entity = boneMap.get(bone.name);
            if (bone.parent) {
                const parent = boneMap.get(bone.parent);
                if (parent) {
                    if (!parent.children)
                        parent.children = [];
                    parent.children.push(entity);
                }
                else {
                    rootBones.push(entity);
                }
            }
            else {
                rootBones.push(entity);
            }
        }
        return rootBones;
    }
    addSlotToEntity(rootEntity, slot, armature) {
        var _a, _b;
        // Find the bone entity
        const boneEntity = this.findBoneEntity(rootEntity, slot.parent);
        if (!boneEntity)
            return;
        // Get display from default skin
        const defaultSkin = armature.skin.find((s) => s.name === 'default') || armature.skin[0];
        const skinSlot = defaultSkin === null || defaultSkin === void 0 ? void 0 : defaultSkin.slot.find((s) => s.name === slot.name);
        const defaultDisplay = skinSlot === null || skinSlot === void 0 ? void 0 : skinSlot.display[(_a = slot.displayIndex) !== null && _a !== void 0 ? _a : 0];
        const slotData = {
            name: slot.name,
            bone: slot.parent,
            displayIndex: (_b = slot.displayIndex) !== null && _b !== void 0 ? _b : 0,
            blendMode: slot.blendMode || 'normal',
        };
        if (slot.color) {
            slotData.color = this.convertColor(slot.color);
        }
        boneEntity.components.push({
            type: 'Slot',
            data: slotData,
        });
        // Add display component
        if (defaultDisplay) {
            if (defaultDisplay.type === 'mesh') {
                const meshDisplay = defaultDisplay;
                boneEntity.components.push({
                    type: 'Mesh',
                    data: {
                        name: meshDisplay.name,
                        path: meshDisplay.path,
                        vertices: meshDisplay.vertices,
                        uvs: meshDisplay.uvs,
                        triangles: meshDisplay.triangles,
                        weights: meshDisplay.weights,
                        transform: meshDisplay.transform,
                    },
                });
            }
            else if (defaultDisplay.type === 'boundingBox') {
                const bbDisplay = defaultDisplay;
                boneEntity.components.push({
                    type: 'BoundingBox',
                    data: {
                        name: bbDisplay.name,
                        subType: bbDisplay.subType || 'rectangle',
                        width: bbDisplay.width,
                        height: bbDisplay.height,
                        vertices: bbDisplay.vertices,
                    },
                });
            }
            else {
                const imageDisplay = defaultDisplay;
                boneEntity.components.push({
                    type: 'Sprite',
                    data: {
                        name: imageDisplay.name,
                        path: imageDisplay.path || imageDisplay.name,
                        pivot: imageDisplay.pivot,
                        transform: imageDisplay.transform,
                    },
                });
            }
        }
    }
    findBoneEntity(entity, boneName) {
        var _a;
        if (entity.name === boneName)
            return entity;
        for (const child of (_a = entity.children) !== null && _a !== void 0 ? _a : []) {
            const found = this.findBoneEntity(child, boneName);
            if (found)
                return found;
        }
        return null;
    }
    // ----------------------------------------
    // Animation Conversion
    // ----------------------------------------
    convertAnimation(anim, frameRate) {
        var _a, _b, _c, _d;
        return {
            name: anim.name,
            duration: anim.duration / frameRate,
            frameRate,
            playTimes: (_a = anim.playTimes) !== null && _a !== void 0 ? _a : 0,
            fadeInTime: (_b = anim.fadeInTime) !== null && _b !== void 0 ? _b : 0,
            bones: (_c = anim.bone) === null || _c === void 0 ? void 0 : _c.map((timeline) => ({
                name: timeline.name,
                translate: timeline.translateFrame,
                rotate: timeline.rotateFrame,
                scale: timeline.scaleFrame,
                legacy: timeline.frame,
            })),
            slots: (_d = anim.slot) === null || _d === void 0 ? void 0 : _d.map((timeline) => ({
                name: timeline.name,
                display: timeline.displayFrame,
                color: timeline.colorFrame,
                legacy: timeline.frame,
            })),
            ffd: anim.ffd,
            ik: anim.ik,
            zOrder: anim.zOrder,
            events: anim.frame,
        };
    }
    // ----------------------------------------
    // Utilities
    // ----------------------------------------
    convertColor(color) {
        var _a, _b, _c, _d, _e, _f, _g;
        const r = Math.round(255 * ((_a = color.rM) !== null && _a !== void 0 ? _a : 1) + ((_b = color.rO) !== null && _b !== void 0 ? _b : 0));
        const g = Math.round(255 * ((_c = color.gM) !== null && _c !== void 0 ? _c : 1) + ((_d = color.gO) !== null && _d !== void 0 ? _d : 0));
        const b = Math.round(255 * ((_e = color.bM) !== null && _e !== void 0 ? _e : 1) + ((_f = color.bO) !== null && _f !== void 0 ? _f : 0));
        const a = (_g = color.aM) !== null && _g !== void 0 ? _g : 1;
        if (a < 1) {
            return `rgba(${r}, ${g}, ${b}, ${a})`;
        }
        return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
    }
    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');
    }
}
// ============================================================
// Factory Function
// ============================================================
function createDragonBonesImporter() {
    return new DragonBonesImporter();
}

exports.DragonBonesImporter = DragonBonesImporter;
exports.createDragonBonesImporter = createDragonBonesImporter;
//# sourceMappingURL=DragonBonesImporter.js.map
