import { PlatformExporter } from './PlatformExporter.js';
import { CSharpExporter } from '../scripting/exporters/CSharpExporter.js';
import { GraphToAST } from '../scripting/GraphToAST.js';

/* ────────────────────────────────────────────────────────────────
   Unity Package Exporter
   
   Exports Nice2Dev projects to Unity .unitypackage format.
   Generates C# scripts, prefabs, scenes, and materials.
──────────────────────────────────────────────────────────────── */
/* ── Unity Exporter Class ─────────────────────────────────────── */
class UnityExporter extends PlatformExporter {
    constructor() {
        super(...arguments);
        this.platformId = 'unity';
        this.platformInfo = {
            id: 'unity',
            name: 'Unity',
            description: 'Professional game engine for 2D and 3D games',
            website: 'https://unity.com',
            features: [
                '2d-rendering',
                '3d-rendering',
                'physics-2d',
                'physics-3d',
                'audio',
                'networking',
                'ui-system',
                'visual-scripting',
                'particles',
                'animation',
                'vr-ar',
            ],
            supportedAssets: [
                'sprite',
                'tileset',
                'audio',
                'font',
                'script',
                'scene',
                'prefab',
                'material',
                'shader',
                'animation',
                'particleSystem',
            ],
            exportFormats: ['.unitypackage', '.prefab', '.unity', '.cs'],
        };
        this.csharpExporter = new CSharpExporter();
        this.graphToAST = new GraphToAST();
        this.guidMap = new Map();
        this.fileIdCounter = 100000;
    }
    async doExport(project, options) {
        const unity = options.platformOptions;
        const projectName = options.projectName || project.name;
        const ns = (unity === null || unity === void 0 ? void 0 : unity.namespace) || this.toValidNamespace(projectName);
        // Generate GUIDs for all assets
        this.generateGuids(project);
        // 1. Generate project structure
        await this.exportProjectSettings(project, options, unity);
        // 2. Export scripts
        await this.exportScripts(project, options, ns);
        // 3. Export prefabs
        await this.exportPrefabs(project, options);
        // 4. Export scenes
        await this.exportScenes(project, options);
        // 5. Export materials
        await this.exportMaterials(project, options, unity);
        // 6. Export assets (sprites, audio, etc.)
        await this.exportAssets(project, options);
        // 7. Generate assembly definition
        if ((unity === null || unity === void 0 ? void 0 : unity.generateAsmdef) !== false) {
            this.exportAssemblyDefinition(projectName, ns);
        }
        // 8. Generate Nice2Dev runtime bridge
        if ((unity === null || unity === void 0 ? void 0 : unity.includeRuntime) !== false) {
            this.exportRuntimeBridge(ns);
        }
        // 9. Generate manifest for .unitypackage
        this.exportPackageManifest(project);
    }
    /* ── Project Settings ───────────────────────────────────────── */
    async exportProjectSettings(project, options, unity) {
        var _a;
        // ProjectSettings.asset
        const settings = `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!129 &1
PlayerSettings:
  productName: ${project.name}
  companyName: ${project.author || 'Nice2Dev'}
  defaultScreenWidth: ${project.settings.resolution.width}
  defaultScreenHeight: ${project.settings.resolution.height}
  runInBackground: 1
  colorSpace: 1
  activeInputHandler: 2
  targetGpuSkinning: 1`;
        this.addTextFile(`ProjectSettings/ProjectSettings.asset`, settings);
        this.addTextFile(`ProjectSettings/ProjectSettings.asset.meta`, this.createMetaFile('project-settings'));
        // Physics2DSettings.asset
        if ((_a = project.settings.physics) === null || _a === void 0 ? void 0 : _a.enabled) {
            const gravity = project.settings.physics.gravity;
            const physics2d = `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!19 &1
Physics2DSettings:
  m_Gravity: {x: ${gravity.x}, y: ${gravity.y}}
  m_DefaultMaterial: {fileID: 0}
  m_VelocityIterations: 8
  m_PositionIterations: 3`;
            this.addTextFile(`ProjectSettings/Physics2DSettings.asset`, physics2d);
        }
    }
    /* ── Scripts ────────────────────────────────────────────────── */
    async exportScripts(project, options, namespace) {
        for (const script of project.scripts) {
            try {
                const ast = this.graphToAST.convert(script);
                const result = this.csharpExporter.export(ast, {
                    namespace,
                    includeDebugComments: options.debug,
                });
                for (const file of result.files) {
                    const path = `Assets/Scripts/${file.path}`;
                    this.addTextFile(path, file.content);
                    this.addTextFile(`${path}.meta`, this.createScriptMetaFile(script.id));
                }
            }
            catch (error) {
                this.addWarning('SCRIPT_EXPORT_ERROR', `Failed to export script "${script.name}": ${error}`, 'Check visual script for errors');
            }
        }
    }
    /* ── Prefabs ────────────────────────────────────────────────── */
    async exportPrefabs(project, options) {
        for (const prefab of project.prefabs) {
            const yaml = this.createPrefabYAML(prefab, project);
            const path = `Assets/Prefabs/${this.sanitizeFileName(prefab.name)}.prefab`;
            this.addTextFile(path, yaml);
            this.addTextFile(`${path}.meta`, this.createMetaFile(prefab.id));
        }
    }
    createPrefabYAML(prefab, project) {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const objects = [];
        const rootId = this.nextFileId();
        const transformId = this.nextFileId();
        const gameObjectId = this.nextFileId();
        // PrefabInstance header
        objects.push({
            fileID: rootId,
            classID: 1001, // PrefabInstance
            type: 'PrefabInstance',
            properties: {
                m_ObjectHideFlags: 0,
                m_CorrespondingSourceObject: { fileID: 0 },
                m_PrefabInstance: { fileID: 0 },
                m_PrefabAsset: { fileID: 0 },
            },
        });
        // Root GameObject
        objects.push({
            fileID: gameObjectId,
            classID: 1, // GameObject
            type: 'GameObject',
            properties: {
                m_ObjectHideFlags: 0,
                m_Name: prefab.name,
                m_IsActive: 1,
                m_Layer: 0,
                m_Tag: 'Untagged',
            },
        });
        // Transform component
        objects.push({
            fileID: transformId,
            classID: 4, // Transform
            type: 'Transform',
            properties: {
                m_LocalRotation: { x: 0, y: 0, z: 0, w: 1 },
                m_LocalPosition: {
                    x: (_b = (_a = prefab.entity.position) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0,
                    y: (_d = (_c = prefab.entity.position) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0,
                    z: 0,
                },
                m_LocalScale: { x: (_f = (_e = prefab.entity.scale) === null || _e === void 0 ? void 0 : _e.x) !== null && _f !== void 0 ? _f : 1, y: (_h = (_g = prefab.entity.scale) === null || _g === void 0 ? void 0 : _g.y) !== null && _h !== void 0 ? _h : 1, z: 1 },
                m_Children: [],
                m_Father: { fileID: 0 },
                m_RootOrder: 0,
            },
        });
        // Add components based on entity type
        this.addEntityComponents(prefab.entity, objects, gameObjectId, project);
        return this.serializeUnityYAML({ objects });
    }
    /* ── Scenes ─────────────────────────────────────────────────── */
    async exportScenes(project, options) {
        for (const scene of project.scenes) {
            const yaml = this.createSceneYAML(scene, project);
            const path = `Assets/Scenes/${this.sanitizeFileName(scene.name)}.unity`;
            this.addTextFile(path, yaml);
            this.addTextFile(`${path}.meta`, this.createMetaFile(scene.id));
        }
    }
    createSceneYAML(scene, project) {
        var _a;
        const objects = [];
        // Scene settings (OcclusionCullingSettings, RenderSettings, etc.)
        this.addSceneSettings(objects, project);
        // Create hierarchy of GameObjects
        for (const entity of scene.entities) {
            this.createGameObjectHierarchy(entity, objects, project, null);
        }
        // Handle tilemaps
        for (const tilemap of (_a = scene.tilemaps) !== null && _a !== void 0 ? _a : []) {
            this.createTilemapGameObject(tilemap, objects, project);
        }
        return this.serializeUnityYAML({ objects });
    }
    addSceneSettings(objects, project) {
        // OcclusionCullingSettings
        objects.push({
            fileID: 1,
            classID: 29,
            type: 'OcclusionCullingSettings',
            properties: {},
        });
        // RenderSettings
        const bgColor = this.parseColor(project.settings.backgroundColor);
        objects.push({
            fileID: 2,
            classID: 104,
            type: 'RenderSettings',
            properties: {
                m_AmbientSkyColor: bgColor,
                m_AmbientEquatorColor: bgColor,
                m_AmbientGroundColor: bgColor,
            },
        });
        // LightmapSettings
        objects.push({
            fileID: 3,
            classID: 157,
            type: 'LightmapSettings',
            properties: {},
        });
        // NavMeshSettings
        objects.push({
            fileID: 4,
            classID: 196,
            type: 'NavMeshSettings',
            properties: {},
        });
    }
    createGameObjectHierarchy(entity, objects, project, parentTransformId) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        const gameObjectId = this.nextFileId();
        const transformId = this.nextFileId();
        // GameObject
        objects.push({
            fileID: gameObjectId,
            classID: 1,
            type: 'GameObject',
            properties: {
                m_ObjectHideFlags: 0,
                m_Name: entity.name,
                m_IsActive: 1,
                m_Layer: 0,
                m_Tag: 'Untagged',
            },
        });
        // Process children for transform hierarchy
        const childTransformIds = [];
        if (entity.children) {
            for (const child of entity.children) {
                const childTransformId = this.createGameObjectHierarchy(child, objects, project, transformId);
                childTransformIds.push(childTransformId);
            }
        }
        // Transform component
        const isRectTransform = entity.components.some((c) => c.type === 'ui-text' || c.type === 'ui-button' || c.type === 'ui-image');
        objects.push({
            fileID: transformId,
            classID: isRectTransform ? 224 : 4, // RectTransform or Transform
            type: isRectTransform ? 'RectTransform' : 'Transform',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_LocalRotation: {
                    x: 0,
                    y: 0,
                    z: Math.sin(((_a = entity.rotation) !== null && _a !== void 0 ? _a : 0) / 2),
                    w: Math.cos(((_b = entity.rotation) !== null && _b !== void 0 ? _b : 0) / 2),
                },
                m_LocalPosition: { x: (_d = (_c = entity.position) === null || _c === void 0 ? void 0 : _c.x) !== null && _d !== void 0 ? _d : 0, y: (_f = (_e = entity.position) === null || _e === void 0 ? void 0 : _e.y) !== null && _f !== void 0 ? _f : 0, z: 0 },
                m_LocalScale: { x: (_h = (_g = entity.scale) === null || _g === void 0 ? void 0 : _g.x) !== null && _h !== void 0 ? _h : 1, y: (_k = (_j = entity.scale) === null || _j === void 0 ? void 0 : _j.y) !== null && _k !== void 0 ? _k : 1, z: 1 },
                m_Children: childTransformIds.map((id) => ({ fileID: id })),
                m_Father: parentTransformId ? { fileID: parentTransformId } : { fileID: 0 },
                m_RootOrder: 0,
            },
        });
        // Add other components
        this.addEntityComponents(entity, objects, gameObjectId, project);
        return transformId;
    }
    addEntityComponents(entity, objects, gameObjectId, project) {
        var _a;
        for (const component of entity.components) {
            const props = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
            switch (component.type) {
                case 'sprite':
                    this.addSpriteRenderer(objects, gameObjectId, props);
                    break;
                case 'rigidbody-2d':
                    this.addRigidbody2D(objects, gameObjectId, props);
                    break;
                case 'box-collider-2d':
                    this.addBoxCollider2D(objects, gameObjectId, props);
                    break;
                case 'circle-collider-2d':
                    this.addCircleCollider2D(objects, gameObjectId, props);
                    break;
                case 'audio-source':
                    this.addAudioSource(objects, gameObjectId, props);
                    break;
                case 'animator':
                    this.addAnimator(objects, gameObjectId, props);
                    break;
                case 'ui-text':
                    this.addUIText(objects, gameObjectId, props);
                    break;
                case 'ui-image':
                    this.addUIImage(objects, gameObjectId, props);
                    break;
                case 'ui-button':
                    this.addUIButton(objects, gameObjectId, props);
                    break;
                case 'particle-system':
                    this.addParticleSystem(objects, gameObjectId, props);
                    break;
                default:
                    this.addWarning('UNKNOWN_COMPONENT', `Unknown component type "${component.type}" on entity "${entity.name}"`, 'Component will be skipped');
            }
        }
        // Add script component if entity has one
        if (entity.scriptId) {
            this.addScriptComponent(objects, gameObjectId, entity.scriptId);
        }
    }
    /* ── Component Generators ───────────────────────────────────── */
    addSpriteRenderer(objects, gameObjectId, props) {
        var _a, _b;
        const componentId = this.nextFileId();
        const spriteId = props.spriteId;
        objects.push({
            fileID: componentId,
            classID: 212, // SpriteRenderer
            type: 'SpriteRenderer',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Sprite: spriteId
                    ? { fileID: 21300000, guid: this.guidMap.get(spriteId) || '', type: 3 }
                    : { fileID: 0 },
                m_Color: this.parseColor((_a = props.color) !== null && _a !== void 0 ? _a : '#ffffff'),
                m_FlipX: props.flipX ? 1 : 0,
                m_FlipY: props.flipY ? 1 : 0,
                m_SortingLayerID: 0,
                m_SortingOrder: (_b = props.sortingOrder) !== null && _b !== void 0 ? _b : 0,
            },
        });
    }
    addRigidbody2D(objects, gameObjectId, props) {
        var _a, _b, _c, _d;
        const componentId = this.nextFileId();
        objects.push({
            fileID: componentId,
            classID: 50, // Rigidbody2D
            type: 'Rigidbody2D',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_BodyType: props.type === 'static' ? 2 : props.type === 'kinematic' ? 1 : 0,
                m_Mass: (_a = props.mass) !== null && _a !== void 0 ? _a : 1,
                m_LinearDrag: (_b = props.linearDrag) !== null && _b !== void 0 ? _b : 0,
                m_AngularDrag: (_c = props.angularDrag) !== null && _c !== void 0 ? _c : 0.05,
                m_GravityScale: (_d = props.gravityScale) !== null && _d !== void 0 ? _d : 1,
                m_FreezeRotation: props.freezeRotation ? 1 : 0,
                m_Interpolate: 0,
                m_SleepingMode: 1,
                m_CollisionDetection: 0,
            },
        });
    }
    addBoxCollider2D(objects, gameObjectId, props) {
        var _a, _b, _c, _d;
        const componentId = this.nextFileId();
        objects.push({
            fileID: componentId,
            classID: 61, // BoxCollider2D
            type: 'BoxCollider2D',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_IsTrigger: props.isTrigger ? 1 : 0,
                m_Size: { x: (_a = props.width) !== null && _a !== void 0 ? _a : 1, y: (_b = props.height) !== null && _b !== void 0 ? _b : 1 },
                m_Offset: { x: (_c = props.offsetX) !== null && _c !== void 0 ? _c : 0, y: (_d = props.offsetY) !== null && _d !== void 0 ? _d : 0 },
            },
        });
    }
    addCircleCollider2D(objects, gameObjectId, props) {
        var _a, _b, _c;
        const componentId = this.nextFileId();
        objects.push({
            fileID: componentId,
            classID: 58, // CircleCollider2D
            type: 'CircleCollider2D',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_IsTrigger: props.isTrigger ? 1 : 0,
                m_Radius: (_a = props.radius) !== null && _a !== void 0 ? _a : 0.5,
                m_Offset: { x: (_b = props.offsetX) !== null && _b !== void 0 ? _b : 0, y: (_c = props.offsetY) !== null && _c !== void 0 ? _c : 0 },
            },
        });
    }
    addAudioSource(objects, gameObjectId, props) {
        var _a, _b, _c;
        const componentId = this.nextFileId();
        const audioClipId = props.clipId;
        objects.push({
            fileID: componentId,
            classID: 82, // AudioSource
            type: 'AudioSource',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_AudioClip: audioClipId
                    ? { fileID: 8300000, guid: this.guidMap.get(audioClipId) || '', type: 3 }
                    : { fileID: 0 },
                m_PlayOnAwake: props.playOnAwake ? 1 : 0,
                m_Loop: props.loop ? 1 : 0,
                m_Volume: (_a = props.volume) !== null && _a !== void 0 ? _a : 1,
                m_Pitch: (_b = props.pitch) !== null && _b !== void 0 ? _b : 1,
                m_SpatialBlend: (_c = props.spatialBlend) !== null && _c !== void 0 ? _c : 0,
            },
        });
    }
    addAnimator(objects, gameObjectId, props) {
        var _a;
        const componentId = this.nextFileId();
        const controllerId = props.controllerId;
        objects.push({
            fileID: componentId,
            classID: 95, // Animator
            type: 'Animator',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Controller: controllerId
                    ? { fileID: 9100000, guid: this.guidMap.get(controllerId) || '', type: 2 }
                    : { fileID: 0 },
                m_ApplyRootMotion: props.applyRootMotion ? 1 : 0,
                m_UpdateMode: 0,
                m_CullingMode: (_a = props.cullingMode) !== null && _a !== void 0 ? _a : 0,
            },
        });
    }
    addUIText(objects, gameObjectId, props) {
        var _a, _b, _c;
        const componentId = this.nextFileId();
        // Using TextMeshProUGUI instead of legacy Text
        objects.push({
            fileID: componentId,
            classID: 114, // MonoBehaviour (TextMeshProUGUI)
            type: 'MonoBehaviour',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Script: { fileID: 11500000, guid: 'f4688fdb7df04437aeb418b961361dc5', type: 3 }, // TMP_Text
                m_Text: (_a = props.text) !== null && _a !== void 0 ? _a : '',
                m_FontSize: (_b = props.fontSize) !== null && _b !== void 0 ? _b : 24,
                m_FontColor: this.parseColor((_c = props.color) !== null && _c !== void 0 ? _c : '#ffffff'),
                m_TextAlignment: this.getTextAlignment(props.alignment),
            },
        });
    }
    addUIImage(objects, gameObjectId, props) {
        var _a, _b;
        const componentId = this.nextFileId();
        const spriteId = props.spriteId;
        objects.push({
            fileID: componentId,
            classID: 114, // Image
            type: 'Image',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Sprite: spriteId
                    ? { fileID: 21300000, guid: this.guidMap.get(spriteId) || '', type: 3 }
                    : { fileID: 0 },
                m_Color: this.parseColor((_a = props.color) !== null && _a !== void 0 ? _a : '#ffffff'),
                m_RaycastTarget: props.raycastTarget !== false ? 1 : 0,
                m_Type: (_b = props.imageType) !== null && _b !== void 0 ? _b : 0, // Simple
                m_FillCenter: 1,
                m_PreserveAspect: props.preserveAspect ? 1 : 0,
            },
        });
    }
    addUIButton(objects, gameObjectId, props) {
        const componentId = this.nextFileId();
        objects.push({
            fileID: componentId,
            classID: 114, // Button
            type: 'Button',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Interactable: props.interactable !== false ? 1 : 0,
                m_TargetGraphic: { fileID: 0 },
                m_OnClick: { m_PersistentCalls: { m_Calls: [] } },
            },
        });
    }
    addParticleSystem(objects, gameObjectId, props) {
        var _a, _b, _c, _d, _e, _f;
        const componentId = this.nextFileId();
        objects.push({
            fileID: componentId,
            classID: 198, // ParticleSystem
            type: 'ParticleSystem',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Duration: (_a = props.duration) !== null && _a !== void 0 ? _a : 5,
                m_Looping: props.looping ? 1 : 0,
                m_Prewarm: props.prewarm ? 1 : 0,
                m_StartDelay: { value: (_b = props.startDelay) !== null && _b !== void 0 ? _b : 0 },
                m_PlayOnAwake: props.playOnAwake !== false ? 1 : 0,
                m_StartSpeed: { value: (_c = props.startSpeed) !== null && _c !== void 0 ? _c : 5 },
                m_StartSize: { value: (_d = props.startSize) !== null && _d !== void 0 ? _d : 1 },
                m_StartColor: this.parseColor((_e = props.startColor) !== null && _e !== void 0 ? _e : '#ffffff'),
                m_MaxParticles: (_f = props.maxParticles) !== null && _f !== void 0 ? _f : 1000,
            },
        });
    }
    addScriptComponent(objects, gameObjectId, scriptId) {
        const componentId = this.nextFileId();
        const scriptGuid = this.guidMap.get(scriptId);
        if (!scriptGuid) {
            this.addWarning('SCRIPT_NOT_FOUND', `Script "${scriptId}" not found for entity`);
            return;
        }
        objects.push({
            fileID: componentId,
            classID: 114, // MonoBehaviour
            type: 'MonoBehaviour',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_Script: { fileID: 11500000, guid: scriptGuid, type: 3 },
            },
        });
    }
    /* ── Tilemaps ───────────────────────────────────────────────── */
    createTilemapGameObject(tilemap, objects, project) {
        const gameObjectId = this.nextFileId();
        const transformId = this.nextFileId();
        const gridId = this.nextFileId();
        // Grid GameObject (parent)
        objects.push({
            fileID: gameObjectId,
            classID: 1,
            type: 'GameObject',
            properties: {
                m_ObjectHideFlags: 0,
                m_Name: tilemap.name,
                m_IsActive: 1,
                m_Layer: 0,
                m_Tag: 'Untagged',
            },
        });
        // Grid component
        objects.push({
            fileID: gridId,
            classID: 156, // Grid
            type: 'Grid',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_CellSize: { x: tilemap.tileSize, y: tilemap.tileSize, z: 0 },
                m_CellGap: { x: 0, y: 0, z: 0 },
                m_CellLayout: 0, // Rectangle
                m_CellSwizzle: 0, // XYZ
            },
        });
        // Transform for grid
        objects.push({
            fileID: transformId,
            classID: 4,
            type: 'Transform',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_LocalRotation: { x: 0, y: 0, z: 0, w: 1 },
                m_LocalPosition: { x: 0, y: 0, z: 0 },
                m_LocalScale: { x: 1, y: 1, z: 1 },
                m_Children: [],
                m_Father: { fileID: 0 },
                m_RootOrder: 0,
            },
        });
        // Create Tilemap layer objects
        for (let i = 0; i < tilemap.layers.length; i++) {
            this.createTilemapLayer(tilemap.layers[i], tilemap, objects, transformId, project);
        }
    }
    createTilemapLayer(layer, tilemap, objects, parentTransformId, project) {
        const gameObjectId = this.nextFileId();
        const transformId = this.nextFileId();
        const tilemapId = this.nextFileId();
        const rendererId = this.nextFileId();
        // Layer GameObject
        objects.push({
            fileID: gameObjectId,
            classID: 1,
            type: 'GameObject',
            properties: {
                m_Name: layer.name,
                m_IsActive: layer.visible ? 1 : 0,
            },
        });
        // Transform
        objects.push({
            fileID: transformId,
            classID: 4,
            type: 'Transform',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Father: { fileID: parentTransformId },
            },
        });
        // Tilemap component
        objects.push({
            fileID: tilemapId,
            classID: 156, // Tilemap
            type: 'Tilemap',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Size: { x: tilemap.width, y: tilemap.height, z: 1 },
                m_TileAssets: [], // Would reference TileBase assets
                m_TileMatrixArray: [],
                m_TileColorArray: [],
            },
        });
        // TilemapRenderer
        objects.push({
            fileID: rendererId,
            classID: 156, // TilemapRenderer
            type: 'TilemapRenderer',
            properties: {
                m_GameObject: { fileID: gameObjectId },
                m_Enabled: 1,
                m_SortingLayerID: 0,
                m_SortingOrder: 0,
                m_ChunkSize: { x: 32, y: 32, z: 1 },
            },
        });
    }
    /* ── Materials ──────────────────────────────────────────────── */
    async exportMaterials(project, options, unity) {
        const materials = project.assets.filter((a) => a.type === 'material');
        for (const material of materials) {
            const matYaml = this.createMaterialYAML(material, unity === null || unity === void 0 ? void 0 : unity.useURP);
            const path = `Assets/Materials/${this.sanitizeFileName(material.name)}.mat`;
            this.addTextFile(path, matYaml);
            this.addTextFile(`${path}.meta`, this.createMetaFile(material.id));
        }
    }
    createMaterialYAML(material, useURP) {
        var _a, _b;
        const shaderGuid = useURP
            ? '933532a4fcc9baf4fa0491de14d08ed7' // Universal Render Pipeline/Lit
            : '0000000000000000f000000000000000'; // Standard
        const color = (_b = (_a = material.metadata) === null || _a === void 0 ? void 0 : _a.color) !== null && _b !== void 0 ? _b : '#ffffff';
        const rgba = this.parseColor(color);
        return `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
  serializedVersion: 8
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_Name: ${material.name}
  m_Shader: {fileID: 46, guid: ${shaderGuid}, type: 2}
  m_Parent: {fileID: 0}
  m_Color: ${JSON.stringify(rgba)}`;
    }
    /* ── Assets ─────────────────────────────────────────────────── */
    async exportAssets(project, options) {
        for (const asset of project.assets) {
            switch (asset.type) {
                case 'sprite':
                    this.exportSpriteAsset(asset);
                    break;
                case 'audio':
                    this.exportAudioAsset(asset);
                    break;
                case 'font':
                    this.exportFontAsset(asset);
                    break;
                case 'tileset':
                    this.exportTilesetAsset(asset);
                    break;
                case 'animation':
                    this.exportAnimationAsset(asset);
                    break;
            }
        }
    }
    exportSpriteAsset(asset) {
        // Create .meta file for sprite import settings
        const meta = `fileFormatVersion: 2
guid: ${this.guidMap.get(asset.id)}
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 12
  mipmaps:
    mipMapMode: 0
    enableMipMap: 0
  bumpmap:
    convertToNormalMap: 0
  isReadable: 0
  streamingMipmaps: 0
  spriteMode: 1
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 1
  spriteTessellationDetail: -1
  textureType: 8
  textureShape: 1
  filterMode: 0
  maxTextureSize: 2048
  textureCompression: 1`;
        const path = `Assets/Sprites/${this.sanitizeFileName(asset.name)}`;
        // Note: actual image file would be copied from source
        this.addTextFile(`${path}.meta`, meta);
    }
    exportAudioAsset(asset) {
        const meta = `fileFormatVersion: 2
guid: ${this.guidMap.get(asset.id)}
AudioImporter:
  externalObjects: {}
  serializedVersion: 7
  defaultSettings:
    loadType: 0
    sampleRateSetting: 0
    sampleRateOverride: 44100
    compressionFormat: 1
    quality: 1
    conversionMode: 0
  forceToMono: 0
  normalize: 1
  preloadAudioData: 1
  loadInBackground: 0
  ambisonic: 0
  3D: 1`;
        const path = `Assets/Audio/${this.sanitizeFileName(asset.name)}`;
        this.addTextFile(`${path}.meta`, meta);
    }
    exportFontAsset(asset) {
        const meta = `fileFormatVersion: 2
guid: ${this.guidMap.get(asset.id)}
TrueTypeFontImporter:
  externalObjects: {}
  serializedVersion: 4
  fontSize: 16
  forceTextureCase: -2
  characterSpacing: 0
  characterPadding: 1
  includeFontData: 1
  fontNames:
  - ${asset.name}
  fallbackFontReferences: []
  customCharacters:
  fontRenderingMode: 0
  ascentCalculationMode: 1`;
        const path = `Assets/Fonts/${this.sanitizeFileName(asset.name)}`;
        this.addTextFile(`${path}.meta`, meta);
    }
    exportTilesetAsset(asset) {
        // Export as Tileset Palette
        const palette = `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_Name: ${asset.name}
  m_EditorClassIdentifier: 
  m_Tileset: {fileID: 0}`;
        const path = `Assets/Tilesets/${this.sanitizeFileName(asset.name)}.asset`;
        this.addTextFile(path, palette);
        this.addTextFile(`${path}.meta`, this.createMetaFile(asset.id));
    }
    exportAnimationAsset(asset) {
        const meta = asset.metadata || {};
        const frameRate = meta.frameRate || 12;
        // Basic Animation Clip
        const clip = `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
  m_ObjectHideFlags: 0
  m_Name: ${asset.name}
  serializedVersion: 7
  m_Legacy: 0
  m_Compressed: 0
  m_UseHighQualityCurve: 1
  m_RotationCurves: []
  m_CompressedRotationCurves: []
  m_EulerCurves: []
  m_PositionCurves: []
  m_ScaleCurves: []
  m_FloatCurves: []
  m_PPtrCurves: []
  m_SampleRate: ${frameRate}
  m_WrapMode: 0
  m_Bounds:
    m_Center: {x: 0, y: 0, z: 0}
    m_Extent: {x: 0, y: 0, z: 0}
  m_ClipBindingConstant:
    genericBindings: []
    pptrCurveMapping: []
  m_Events: []`;
        const path = `Assets/Animations/${this.sanitizeFileName(asset.name)}.anim`;
        this.addTextFile(path, clip);
        this.addTextFile(`${path}.meta`, this.createMetaFile(asset.id));
    }
    /* ── Assembly Definition ────────────────────────────────────── */
    exportAssemblyDefinition(projectName, namespace) {
        const asmdef = {
            name: namespace,
            rootNamespace: namespace,
            references: ['Unity.TextMeshPro', 'Unity.InputSystem'],
            includePlatforms: [],
            excludePlatforms: [],
            allowUnsafeCode: false,
            overrideReferences: false,
            precompiledReferences: [],
            autoReferenced: true,
            defineConstraints: [],
            versionDefines: [],
            noEngineReferences: false,
        };
        const path = `Assets/Scripts/${namespace}.asmdef`;
        this.addTextFile(path, JSON.stringify(asmdef, null, 2));
        this.addTextFile(`${path}.meta`, this.createMetaFile('asmdef'));
    }
    /* ── Runtime Bridge ─────────────────────────────────────────── */
    exportRuntimeBridge(namespace) {
        const bridge = `using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

namespace ${namespace}.Runtime
{
    /// <summary>
    /// Bridge between Nice2Dev runtime and Unity systems.
    /// Auto-generated by Nice2Dev export.
    /// </summary>
    public static class Nice2DevBridge
    {
        private static Dictionary<string, GameObject> _entityMap = new();
        private static Dictionary<string, Action<object>> _eventHandlers = new();

        /// <summary>
        /// Register an entity for cross-reference.
        /// </summary>
        public static void RegisterEntity(string id, GameObject obj)
        {
            _entityMap[id] = obj;
        }

        /// <summary>
        /// Get entity by ID.
        /// </summary>
        public static GameObject GetEntity(string id)
        {
            return _entityMap.TryGetValue(id, out var obj) ? obj : null;
        }

        /// <summary>
        /// Emit a custom event.
        /// </summary>
        public static void EmitEvent(string eventName, object data = null)
        {
            if (_eventHandlers.TryGetValue(eventName, out var handler))
            {
                handler?.Invoke(data);
            }
        }

        /// <summary>
        /// Subscribe to a custom event.
        /// </summary>
        public static void OnEvent(string eventName, Action<object> handler)
        {
            if (!_eventHandlers.ContainsKey(eventName))
            {
                _eventHandlers[eventName] = handler;
            }
            else
            {
                _eventHandlers[eventName] += handler;
            }
        }

        /// <summary>
        /// Unsubscribe from a custom event.
        /// </summary>
        public static void OffEvent(string eventName, Action<object> handler)
        {
            if (_eventHandlers.ContainsKey(eventName))
            {
                _eventHandlers[eventName] -= handler;
            }
        }

        /// <summary>
        /// Wait for seconds (coroutine helper).
        /// </summary>
        public static IEnumerator Wait(float seconds)
        {
            yield return new WaitForSeconds(seconds);
        }

        /// <summary>
        /// Spawn a prefab at position.
        /// </summary>
        public static GameObject Spawn(GameObject prefab, Vector2 position)
        {
            return UnityEngine.Object.Instantiate(prefab, new Vector3(position.x, position.y, 0), Quaternion.identity);
        }

        /// <summary>
        /// Destroy an entity.
        /// </summary>
        public static void Destroy(GameObject obj, float delay = 0f)
        {
            if (delay > 0)
            {
                UnityEngine.Object.Destroy(obj, delay);
            }
            else
            {
                UnityEngine.Object.Destroy(obj);
            }
        }

        /// <summary>
        /// Play audio clip.
        /// </summary>
        public static void PlaySound(AudioClip clip, float volume = 1f)
        {
            AudioSource.PlayClipAtPoint(clip, Camera.main.transform.position, volume);
        }

        /// <summary>
        /// Get input axis.
        /// </summary>
        public static float GetAxis(string axisName)
        {
            return Input.GetAxis(axisName);
        }

        /// <summary>
        /// Check if key is pressed.
        /// </summary>
        public static bool IsKeyPressed(KeyCode key)
        {
            return Input.GetKey(key);
        }

        /// <summary>
        /// Check if key was just pressed.
        /// </summary>
        public static bool IsKeyJustPressed(KeyCode key)
        {
            return Input.GetKeyDown(key);
        }

        /// <summary>
        /// Get mouse position in world space.
        /// </summary>
        public static Vector2 GetMouseWorldPosition()
        {
            if (Camera.main == null) return Vector2.zero;
            return Camera.main.ScreenToWorldPoint(Input.mousePosition);
        }

        /// <summary>
        /// Linear interpolation.
        /// </summary>
        public static float Lerp(float a, float b, float t)
        {
            return Mathf.Lerp(a, b, t);
        }

        /// <summary>
        /// Random float between min and max.
        /// </summary>
        public static float Random(float min, float max)
        {
            return UnityEngine.Random.Range(min, max);
        }

        /// <summary>
        /// Random int between min and max (exclusive).
        /// </summary>
        public static int RandomInt(int min, int max)
        {
            return UnityEngine.Random.Range(min, max);
        }
    }
}`;
        const path = `Assets/Scripts/Runtime/Nice2DevBridge.cs`;
        this.addTextFile(path, bridge);
        this.addTextFile(`${path}.meta`, this.createScriptMetaFile('nice2dev-bridge'));
    }
    /* ── Package Manifest ───────────────────────────────────────── */
    exportPackageManifest(project) {
        // Create .unitypackage manifest
        const manifest = {
            packageName: project.name,
            version: project.version,
            exportedAt: new Date().toISOString(),
            files: this.files.map((f) => f.path),
        };
        this.addTextFile('package.json', JSON.stringify(manifest, null, 2));
    }
    /* ── YAML Serialization ─────────────────────────────────────── */
    serializeUnityYAML(yaml) {
        let output = `%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
`;
        for (const obj of yaml.objects) {
            output += `--- !u!${obj.classID} &${obj.fileID}\n`;
            output += `${obj.type}:\n`;
            output += this.serializeYAMLObject(obj.properties, 1);
        }
        return output;
    }
    serializeYAMLObject(obj, indent) {
        const spaces = '  '.repeat(indent);
        let output = '';
        for (const [key, value] of Object.entries(obj)) {
            if (value === null || value === undefined) {
                output += `${spaces}${key}: \n`;
            }
            else if (typeof value === 'object' && !Array.isArray(value)) {
                const inner = value;
                if (Object.keys(inner).length === 0) {
                    output += `${spaces}${key}: {}\n`;
                }
                else if ('fileID' in inner) {
                    output += `${spaces}${key}: {fileID: ${inner.fileID}${inner.guid ? `, guid: ${inner.guid}` : ''}${inner.type ? `, type: ${inner.type}` : ''}}\n`;
                }
                else if ('x' in inner && 'y' in inner) {
                    const z = 'z' in inner ? `, z: ${inner.z}` : '';
                    const w = 'w' in inner ? `, w: ${inner.w}` : '';
                    output += `${spaces}${key}: {x: ${inner.x}, y: ${inner.y}${z}${w}}\n`;
                }
                else if ('r' in inner && 'g' in inner) {
                    output += `${spaces}${key}: {r: ${inner.r}, g: ${inner.g}, b: ${inner.b}, a: ${inner.a}}\n`;
                }
                else {
                    output += `${spaces}${key}:\n`;
                    output += this.serializeYAMLObject(inner, indent + 1);
                }
            }
            else if (Array.isArray(value)) {
                if (value.length === 0) {
                    output += `${spaces}${key}: []\n`;
                }
                else {
                    output += `${spaces}${key}:\n`;
                    for (const item of value) {
                        if (typeof item === 'object' && item !== null) {
                            output += `${spaces}- `;
                            const itemStr = this.serializeYAMLObject(item, indent + 1);
                            output += itemStr.trim().replace(/\n/g, `\n${spaces}  `) + '\n';
                        }
                        else {
                            output += `${spaces}- ${item}\n`;
                        }
                    }
                }
            }
            else {
                output += `${spaces}${key}: ${value}\n`;
            }
        }
        return output;
    }
    /* ── Utility Methods ────────────────────────────────────────── */
    generateGuids(project) {
        for (const script of project.scripts) {
            this.guidMap.set(script.id, this.generateGUID());
        }
        for (const asset of project.assets) {
            this.guidMap.set(asset.id, this.generateGUID());
        }
        for (const prefab of project.prefabs) {
            this.guidMap.set(prefab.id, this.generateGUID());
        }
        for (const scene of project.scenes) {
            this.guidMap.set(scene.id, this.generateGUID());
        }
    }
    generateGUID() {
        // Unity uses 32-character hex GUIDs
        return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));
    }
    nextFileId() {
        return this.fileIdCounter++;
    }
    createMetaFile(id) {
        const guid = this.guidMap.get(id) || this.generateGUID();
        return `fileFormatVersion: 2
guid: ${guid}
NativeFormatImporter:
  externalObjects: {}
  mainObjectFileID: 0`;
    }
    createScriptMetaFile(scriptId) {
        const guid = this.guidMap.get(scriptId) || this.generateGUID();
        return `fileFormatVersion: 2
guid: ${guid}
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}`;
    }
    parseColor(hex) {
        const clean = hex.replace('#', '');
        const r = parseInt(clean.slice(0, 2), 16) / 255;
        const g = parseInt(clean.slice(2, 4), 16) / 255;
        const b = parseInt(clean.slice(4, 6), 16) / 255;
        const a = clean.length > 6 ? parseInt(clean.slice(6, 8), 16) / 255 : 1;
        return { r, g, b, a };
    }
    sanitizeFileName(name) {
        return name.replace(/[^a-zA-Z0-9_-]/g, '_');
    }
    toValidNamespace(name) {
        return name.replace(/[^a-zA-Z0-9]/g, '').replace(/^[0-9]/, '_$&');
    }
    getTextAlignment(alignment) {
        switch (alignment) {
            case 'left':
                return 257;
            case 'center':
                return 258;
            case 'right':
                return 260;
            case 'top-left':
                return 257;
            case 'top-center':
                return 258;
            case 'top-right':
                return 260;
            case 'bottom-left':
                return 4097;
            case 'bottom-center':
                return 4098;
            case 'bottom-right':
                return 4100;
            default:
                return 258; // center
        }
    }
}

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