'use strict';

var PlatformExporter = require('./PlatformExporter.js');
var TypeScriptExporter = require('../scripting/exporters/TypeScriptExporter.js');
var GraphToAST = require('../scripting/GraphToAST.js');

/* ────────────────────────────────────────────────────────────────
   Three.js Exporter
   
   Exports Nice2Dev projects to Three.js format for 3D web games.
   Generates ES modules with scene management and entity systems.
──────────────────────────────────────────────────────────────── */
/* ── Three.js Exporter Class ──────────────────────────────────── */
class ThreeJSExporter extends PlatformExporter.PlatformExporter {
    constructor() {
        super(...arguments);
        this.platformId = 'threejs';
        this.platformInfo = {
            id: 'threejs',
            name: 'Three.js',
            description: '3D JavaScript library for WebGL',
            website: 'https://threejs.org',
            features: ['3d-rendering', 'particles', 'animation', 'vr-ar'],
            supportedAssets: ['sprite', 'audio', 'font', 'script', 'material', 'shader', 'animation'],
            exportFormats: ['.html', '.js', '.ts'],
        };
        this.tsExporter = new TypeScriptExporter.TypeScriptExporter();
        this.graphToAST = new GraphToAST.GraphToAST();
    }
    async doExport(project, options) {
        const three = options.platformOptions;
        const useTS = (three === null || three === void 0 ? void 0 : three.typescript) !== false;
        const bundler = (three === null || three === void 0 ? void 0 : three.bundler) || 'vite';
        // 1. Generate package.json
        this.exportPackageJson(project, three);
        // 2. Generate HTML entry
        this.exportIndexHtml(project, three);
        // 3. Generate main game file
        this.exportMainGame(project, options, three, useTS);
        // 4. Export scenes
        this.exportScenes(project, options, useTS);
        // 5. Export scripts
        await this.exportScripts(project, options, useTS);
        // 6. Export utilities
        this.exportUtilities(three, useTS);
        // 7. Export shaders
        this.exportShaders(project);
        // 8. Generate bundler config
        if (bundler !== 'none') {
            this.exportBundlerConfig(bundler, useTS);
        }
        // 9. Generate tsconfig if TypeScript
        if (useTS) {
            this.exportTSConfig();
        }
    }
    exportPackageJson(project, three) {
        const useTS = (three === null || three === void 0 ? void 0 : three.typescript) !== false;
        const bundler = (three === null || three === void 0 ? void 0 : three.bundler) || 'vite';
        const threeVersion = (three === null || three === void 0 ? void 0 : three.version) || '^0.162.0';
        const dependencies = {
            three: threeVersion,
        };
        // Add physics engine
        if ((three === null || three === void 0 ? void 0 : three.physics) === 'cannon') {
            dependencies['cannon-es'] = '^0.20.0';
        }
        else if ((three === null || three === void 0 ? void 0 : three.physics) === 'rapier') {
            dependencies['@dimforge/rapier3d'] = '^0.12.0';
        }
        // Add post-processing
        if (three === null || three === void 0 ? void 0 : three.postProcessing) {
            dependencies['postprocessing'] = '^6.0.0';
        }
        const packageJson = {
            name: project.name.toLowerCase().replace(/\s+/g, '-'),
            version: project.version,
            description: project.description || `${project.name} - 3D game built with Nice2Dev`,
            type: 'module',
            scripts: {
                dev: bundler === 'vite'
                    ? 'vite'
                    : bundler === 'webpack'
                        ? 'webpack serve'
                        : 'parcel index.html',
                build: bundler === 'vite'
                    ? 'vite build'
                    : bundler === 'webpack'
                        ? 'webpack'
                        : 'parcel build index.html',
                preview: bundler === 'vite' ? 'vite preview' : 'serve dist',
            },
            dependencies,
            devDependencies: {
                ...(useTS ? { typescript: '^5.0.0', '@types/three': '^0.162.0' } : {}),
                ...(bundler === 'vite' ? { vite: '^5.0.0' } : {}),
                ...(bundler === 'webpack'
                    ? {
                        webpack: '^5.0.0',
                        'webpack-cli': '^5.0.0',
                        'webpack-dev-server': '^4.0.0',
                        'ts-loader': '^9.0.0',
                    }
                    : {}),
            },
        };
        this.addTextFile('package.json', JSON.stringify(packageJson, null, 2));
    }
    exportIndexHtml(project, three) {
        const html = `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${project.name}</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    html, body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    
    body {
      background-color: ${project.settings.backgroundColor};
    }
    
    #game-container {
      width: 100%;
      height: 100%;
    }
    
    canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    
    #loading-screen {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: ${project.settings.backgroundColor};
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      z-index: 1000;
      transition: opacity 0.5s ease;
    }
    
    #loading-screen.hidden {
      opacity: 0;
      pointer-events: none;
    }
    
    .loading-bar {
      width: 200px;
      height: 4px;
      background: rgba(255, 255, 255, 0.2);
      border-radius: 2px;
      overflow: hidden;
    }
    
    .loading-bar-fill {
      width: 0%;
      height: 100%;
      background: white;
      transition: width 0.3s ease;
    }
    
    .loading-text {
      color: white;
      font-family: sans-serif;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div id="loading-screen">
    <div class="loading-text">Loading...</div>
    <div class="loading-bar">
      <div class="loading-bar-fill" id="loading-progress"></div>
    </div>
  </div>
  <div id="game-container"></div>
  <script type="module" src="/src/main.ts"></script>
</body>
</html>
`;
        this.addTextFile('index.html', html);
    }
    exportMainGame(project, options, three, useTS) {
        var _a, _b, _c, _d, _e, _f;
        const ext = useTS ? 'ts' : 'js';
        const { width, height } = project.settings.resolution;
        const hasPhysics = (three === null || three === void 0 ? void 0 : three.physics) && three.physics !== 'none';
        const hasXR = three === null || three === void 0 ? void 0 : three.xr;
        const hasOrbitControls = three === null || three === void 0 ? void 0 : three.orbitControls;
        const hasPostProcessing = three === null || three === void 0 ? void 0 : three.postProcessing;
        let imports = `import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
`;
        if (hasOrbitControls) {
            imports += `import { OrbitControls } from 'three/addons/controls/OrbitControls.js';\n`;
        }
        if (hasXR) {
            imports += `import { VRButton } from 'three/addons/webxr/VRButton.js';\n`;
        }
        if (hasPostProcessing) {
            imports += `import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
`;
        }
        if (hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon') {
            imports += `import * as CANNON from 'cannon-es';\n`;
        }
        imports += `
import { GameManager } from './game/GameManager${useTS ? '' : '.js'}';
import { AssetLoader } from './game/AssetLoader${useTS ? '' : '.js'}';
import { InputManager } from './game/InputManager${useTS ? '' : '.js'}';
`;
        // Scene imports
        for (const scene of project.scenes) {
            const sceneName = this.sanitizeName(scene.name);
            imports += `import { ${sceneName}Scene } from './scenes/${sceneName}${useTS ? '' : '.js'}';\n`;
        }
        const main = `${imports}

${useTS
            ? `
interface GameConfig {
  container: HTMLElement;
  width: number;
  height: number;
}
`
            : ''}

class Game {
  ${useTS ? 'private renderer: THREE.WebGLRenderer;' : ''}
  ${useTS ? 'private camera: THREE.PerspectiveCamera;' : ''}
  ${useTS ? 'private scene: THREE.Scene;' : ''}
  ${useTS ? 'private clock: THREE.Clock;' : ''}
  ${useTS ? 'private gameManager: GameManager;' : ''}
  ${useTS ? 'private assetLoader: AssetLoader;' : ''}
  ${useTS ? 'private inputManager: InputManager;' : ''}
  ${hasOrbitControls && useTS ? 'private controls: OrbitControls;' : ''}
  ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon' && useTS ? 'private world: CANNON.World;' : ''}
  ${hasPostProcessing && useTS ? 'private composer: EffectComposer;' : ''}

  async init()${useTS ? ': Promise<void>' : ''} {
    const container = document.getElementById('game-container');
    if (!container) throw new Error('Container not found');

    // Initialize renderer
    this.renderer = new THREE.WebGLRenderer({ 
      antialias: ${!((_a = project.settings.rendering) === null || _a === void 0 ? void 0 : _a.pixelArt)},
      alpha: false,
      powerPreference: 'high-performance',
    });
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    this.renderer.outputColorSpace = THREE.SRGBColorSpace;
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
    this.renderer.toneMappingExposure = 1;
    container.appendChild(this.renderer.domElement);

    ${hasXR
            ? `
    // Enable XR
    this.renderer.xr.enabled = true;
    document.body.appendChild(VRButton.createButton(this.renderer));
    `
            : ''}

    // Initialize camera
    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    this.camera.position.set(0, 5, 10);

    // Initialize scene
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color('${project.settings.backgroundColor}');

    ${hasOrbitControls
            ? `
    // Initialize controls
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.enableDamping = true;
    this.controls.dampingFactor = 0.05;
    `
            : ''}

    ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon'
            ? `
    // Initialize physics
    this.world = new CANNON.World();
    this.world.gravity.set(
      ${(_c = (_b = project.settings.physics) === null || _b === void 0 ? void 0 : _b.gravity.x) !== null && _c !== void 0 ? _c : 0},
      ${(_e = (_d = project.settings.physics) === null || _d === void 0 ? void 0 : _d.gravity.y) !== null && _e !== void 0 ? _e : -9.82},
      0
    );
    this.world.broadphase = new CANNON.NaiveBroadphase();
    `
            : ''}

    ${hasPostProcessing
            ? `
    // Initialize post-processing
    this.composer = new EffectComposer(this.renderer);
    this.composer.addPass(new RenderPass(this.scene, this.camera));
    this.composer.addPass(new UnrealBloomPass(
      new THREE.Vector2(window.innerWidth, window.innerHeight),
      0.5, // strength
      0.4, // radius
      0.85 // threshold
    ));
    `
            : ''}

    // Initialize managers
    this.clock = new THREE.Clock();
    this.assetLoader = new AssetLoader();
    this.inputManager = new InputManager();
    this.gameManager = new GameManager(
      this.scene, 
      this.camera, 
      this.assetLoader,
      this.inputManager
      ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon' ? ', this.world' : ''}
    );

    // Load assets
    await this.loadAssets();

    // Load initial scene
    const initialScene = new ${this.sanitizeName(((_f = project.scenes[0]) === null || _f === void 0 ? void 0 : _f.name) || 'Main')}Scene(this.gameManager);
    await initialScene.init();
    this.gameManager.setCurrentScene(initialScene);

    // Hide loading screen
    const loadingScreen = document.getElementById('loading-screen');
    if (loadingScreen) {
      loadingScreen.classList.add('hidden');
    }

    // Handle resize
    window.addEventListener('resize', this.onResize.bind(this));

    // Start game loop
    ${hasXR
            ? `
    this.renderer.setAnimationLoop(this.animate.bind(this));
    `
            : `
    this.animate();
    `}

    console.log('${project.name} initialized!');
  }

  private async loadAssets()${useTS ? ': Promise<void>' : ''} {
    const progressBar = document.getElementById('loading-progress');
    
    const updateProgress = (progress${useTS ? ': number' : ''}) => {
      if (progressBar) {
        progressBar.style.width = \`\${progress * 100}%\`;
      }
    };

    await this.assetLoader.loadAll(updateProgress);
  }

  private animate(${hasXR ? 'time' + (useTS ? ': number' : '') : ''})${useTS ? ': void' : ''} {
    ${hasXR ? '' : 'requestAnimationFrame(this.animate.bind(this));'}

    const delta = this.clock.getDelta();

    ${hasOrbitControls ? 'this.controls.update();' : ''}

    ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon'
            ? `
    // Update physics
    this.world.step(1 / 60, delta, 3);
    `
            : ''}

    // Update game
    this.gameManager.update(delta);

    // Update input
    this.inputManager.update();

    // Render
    ${hasPostProcessing ? 'this.composer.render();' : 'this.renderer.render(this.scene, this.camera);'}
  }

  private onResize()${useTS ? ': void' : ''} {
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    ${hasPostProcessing ? 'this.composer.setSize(window.innerWidth, window.innerHeight);' : ''}
  }
}

// Start game
const game = new Game();
game.init().catch(console.error);
`;
        this.addTextFile(`src/main.${ext}`, main);
    }
    exportScenes(project, options, useTS) {
        for (const scene of project.scenes) {
            this.exportScene(scene, project, useTS);
        }
    }
    exportScene(scene, project, useTS) {
        const ext = useTS ? 'ts' : 'js';
        const sceneName = this.sanitizeName(scene.name);
        let content = `import * as THREE from 'three';
import { GameManager } from '../game/GameManager${useTS ? '' : '.js'}';
${useTS ? `import type { GameScene } from '../game/GameManager';` : ''}

export class ${sceneName}Scene ${useTS ? 'implements GameScene' : ''} {
  ${useTS ? 'public name: string;' : ''}
  ${useTS ? 'public container: THREE.Group;' : ''}
  ${useTS ? 'private gameManager: GameManager;' : ''}
  ${useTS ? 'private entities: Map<string, THREE.Object3D> = new Map();' : ''}
  ${useTS ? 'private lights: THREE.Light[] = [];' : ''}

  constructor(gameManager${useTS ? ': GameManager' : ''}) {
    this.name = '${scene.name}';
    this.gameManager = gameManager;
    this.container = new THREE.Group();
    ${useTS
            ? ''
            : `
    this.entities = new Map();
    this.lights = [];`}
  }

  async init()${useTS ? ': Promise<void>' : ''} {
    // Add default lighting
    this.setupLighting();

    // Create entities
`;
        // Create entities
        for (const entity of scene.entities) {
            content += this.generateEntityCode(entity, project, useTS);
        }
        content += `
    // Add container to scene
    this.gameManager.scene.add(this.container);
  }

  private setupLighting()${useTS ? ': void' : ''} {
    // Ambient light
    const ambient = new THREE.AmbientLight(0xffffff, 0.4);
    this.container.add(ambient);
    this.lights.push(ambient);

    // Directional light (sun)
    const directional = new THREE.DirectionalLight(0xffffff, 0.8);
    directional.position.set(10, 20, 10);
    directional.castShadow = true;
    directional.shadow.mapSize.width = 2048;
    directional.shadow.mapSize.height = 2048;
    directional.shadow.camera.near = 0.1;
    directional.shadow.camera.far = 100;
    directional.shadow.camera.left = -20;
    directional.shadow.camera.right = 20;
    directional.shadow.camera.top = 20;
    directional.shadow.camera.bottom = -20;
    this.container.add(directional);
    this.lights.push(directional);
  }

  update(delta${useTS ? ': number' : ''})${useTS ? ': void' : ''} {
    // Update logic for scene entities
  }

  destroy()${useTS ? ': void' : ''} {
    // Clean up
    this.container.traverse((object) => {
      if (object ${useTS ? 'instanceof THREE.Mesh' : '.isMesh'}) {
        object.geometry.dispose();
        if (Array.isArray(object.material)) {
          object.material.forEach(m => m.dispose());
        } else {
          object.material.dispose();
        }
      }
    });

    this.gameManager.scene.remove(this.container);
    this.entities.clear();
  }
}
`;
        this.addTextFile(`src/scenes/${sceneName}.${ext}`, content);
    }
    generateEntityCode(entity, project, useTS) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        let code = `
    // Entity: ${entity.name}
    {
`;
        // Determine what kind of object to create based on components
        const hasMesh = entity.components.some((c) => c.type === 'mesh' ||
            c.type === 'box' ||
            c.type === 'sphere' ||
            c.type === 'plane' ||
            c.type === 'cylinder');
        const hasModel = entity.components.some((c) => c.type === 'model');
        const hasLight = entity.components.some((c) => c.type.includes('light'));
        if (hasLight) {
            const lightComp = entity.components.find((c) => c.type.includes('light'));
            if (lightComp) {
                code += this.generateLightCode(entity, lightComp, useTS);
            }
        }
        else if (hasModel) {
            const modelComp = entity.components.find((c) => c.type === 'model');
            if (modelComp) {
                code += this.generateModelCode(entity, modelComp, project, useTS);
            }
        }
        else if (hasMesh) {
            code += this.generateMeshCode(entity, project, useTS);
        }
        else {
            // Empty group
            code += `      const entity = new THREE.Group();
      entity.name = '${entity.name}';
`;
        }
        code += `
      entity.position.set(${(_b = (_a = entity.position) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0}, ${(_d = (_c = entity.position) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0}, 0);
      entity.rotation.z = ${(_e = entity.rotation) !== null && _e !== void 0 ? _e : 0};
      entity.scale.set(${(_g = (_f = entity.scale) === null || _f === void 0 ? void 0 : _f.x) !== null && _g !== void 0 ? _g : 1}, ${(_j = (_h = entity.scale) === null || _h === void 0 ? void 0 : _h.y) !== null && _j !== void 0 ? _j : 1}, 1);
      
      this.container.add(entity);
      this.entities.set('${entity.id}', entity);
    }
`;
        // Process children
        if (entity.children) {
            for (const child of entity.children) {
                code += this.generateEntityCode(child, project, useTS);
            }
        }
        return code;
    }
    generateMeshCode(entity, project, useTS) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
        const meshComp = entity.components.find((c) => c.type === 'mesh' ||
            c.type === 'box' ||
            c.type === 'sphere' ||
            c.type === 'plane' ||
            c.type === 'cylinder');
        if (!meshComp)
            return '      const entity = new THREE.Group();\n';
        const meshProps = (_a = meshComp.properties) !== null && _a !== void 0 ? _a : {};
        let geometryCode = '';
        let materialCode = '';
        // Geometry
        switch (meshComp.type) {
            case 'box':
                geometryCode = `new THREE.BoxGeometry(${(_b = meshProps.width) !== null && _b !== void 0 ? _b : 1}, ${(_c = meshProps.height) !== null && _c !== void 0 ? _c : 1}, ${(_d = meshProps.depth) !== null && _d !== void 0 ? _d : 1})`;
                break;
            case 'sphere':
                geometryCode = `new THREE.SphereGeometry(${(_e = meshProps.radius) !== null && _e !== void 0 ? _e : 0.5}, 32, 16)`;
                break;
            case 'plane':
                geometryCode = `new THREE.PlaneGeometry(${(_f = meshProps.width) !== null && _f !== void 0 ? _f : 10}, ${(_g = meshProps.height) !== null && _g !== void 0 ? _g : 10})`;
                break;
            case 'cylinder':
                geometryCode = `new THREE.CylinderGeometry(${(_h = meshProps.radiusTop) !== null && _h !== void 0 ? _h : 0.5}, ${(_j = meshProps.radiusBottom) !== null && _j !== void 0 ? _j : 0.5}, ${(_k = meshProps.height) !== null && _k !== void 0 ? _k : 1}, 32)`;
                break;
            default:
                geometryCode = 'new THREE.BoxGeometry(1, 1, 1)';
        }
        // Material
        const color = (_l = meshProps.color) !== null && _l !== void 0 ? _l : '#ffffff';
        const materialId = meshProps.materialId;
        const material = materialId ? project.assets.find((a) => a.id === materialId) : null;
        if (material) {
            const matColor = (_o = (_m = material.metadata) === null || _m === void 0 ? void 0 : _m.color) !== null && _o !== void 0 ? _o : color;
            materialCode = `new THREE.MeshStandardMaterial({ 
        color: '${matColor}',
        roughness: ${(_q = (_p = material.metadata) === null || _p === void 0 ? void 0 : _p.roughness) !== null && _q !== void 0 ? _q : 0.5},
        metalness: ${(_s = (_r = material.metadata) === null || _r === void 0 ? void 0 : _r.metalness) !== null && _s !== void 0 ? _s : 0.5},
      })`;
        }
        else {
            materialCode = `new THREE.MeshStandardMaterial({ color: '${color}' })`;
        }
        return `      const geometry = ${geometryCode};
      const material = ${materialCode};
      const entity = new THREE.Mesh(geometry, material);
      entity.name = '${entity.name}';
      entity.castShadow = true;
      entity.receiveShadow = true;
`;
    }
    generateModelCode(entity, component, project, useTS) {
        var _a;
        const compProps = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
        const modelPath = compProps.path;
        return `      // Model loading is handled asynchronously
      const entity = new THREE.Group();
      entity.name = '${entity.name}';
      ${modelPath
            ? `
      this.gameManager.assetLoader.getModel('${modelPath}').then(model => {
        entity.add(model.scene.clone());
      });`
            : ''}
`;
    }
    generateLightCode(entity, component, useTS) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        const compProps = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
        const color = (_b = compProps.color) !== null && _b !== void 0 ? _b : '#ffffff';
        const intensity = (_c = compProps.intensity) !== null && _c !== void 0 ? _c : 1;
        switch (component.type) {
            case 'point-light':
                return `      const entity = new THREE.PointLight('${color}', ${intensity}, ${(_d = compProps.distance) !== null && _d !== void 0 ? _d : 100});
      entity.name = '${entity.name}';
      entity.castShadow = ${(_e = compProps.castShadow) !== null && _e !== void 0 ? _e : true};
`;
            case 'spot-light':
                return `      const entity = new THREE.SpotLight('${color}', ${intensity});
      entity.name = '${entity.name}';
      entity.angle = ${(_f = compProps.angle) !== null && _f !== void 0 ? _f : Math.PI / 6};
      entity.penumbra = ${(_g = compProps.penumbra) !== null && _g !== void 0 ? _g : 0.5};
      entity.castShadow = ${(_h = compProps.castShadow) !== null && _h !== void 0 ? _h : true};
`;
            case 'directional-light':
                return `      const entity = new THREE.DirectionalLight('${color}', ${intensity});
      entity.name = '${entity.name}';
      entity.castShadow = ${(_j = compProps.castShadow) !== null && _j !== void 0 ? _j : true};
`;
            case 'ambient-light':
                return `      const entity = new THREE.AmbientLight('${color}', ${intensity});
      entity.name = '${entity.name}';
`;
            case 'hemisphere-light':
                const groundColor = (_k = compProps.groundColor) !== null && _k !== void 0 ? _k : '#444444';
                return `      const entity = new THREE.HemisphereLight('${color}', '${groundColor}', ${intensity});
      entity.name = '${entity.name}';
`;
            default:
                return `      const entity = new THREE.Group();
      entity.name = '${entity.name}';
`;
        }
    }
    async exportScripts(project, options, useTS) {
        for (const script of project.scripts) {
            try {
                const ast = this.graphToAST.convert(script);
                const result = this.tsExporter.export(ast, {
                    includeDebugComments: options.debug,
                });
                for (const file of result.files) {
                    this.addTextFile(`src/scripts/${file.path}`, file.content);
                }
            }
            catch (error) {
                this.addWarning('SCRIPT_EXPORT_ERROR', `Failed to export script "${script.name}": ${error}`);
            }
        }
    }
    exportUtilities(three, useTS) {
        const ext = useTS ? 'ts' : 'js';
        const hasPhysics = (three === null || three === void 0 ? void 0 : three.physics) === 'cannon';
        // GameManager
        const gameManager = `import * as THREE from 'three';
import { AssetLoader } from './AssetLoader${useTS ? '' : '.js'}';
import { InputManager } from './InputManager${useTS ? '' : '.js'}';
${hasPhysics ? `import * as CANNON from 'cannon-es';` : ''}

${useTS
            ? `
export interface GameScene {
  name: string;
  container: THREE.Group;
  init(): Promise<void>;
  update(delta: number): void;
  destroy(): void;
}
`
            : ''}

export class GameManager {
  ${useTS ? 'public scene: THREE.Scene;' : ''}
  ${useTS ? 'public camera: THREE.Camera;' : ''}
  ${useTS ? 'public assetLoader: AssetLoader;' : ''}
  ${useTS ? 'public input: InputManager;' : ''}
  ${hasPhysics && useTS ? 'public world: CANNON.World;' : ''}
  ${useTS ? 'private currentScene: GameScene | null = null;' : ''}
  ${useTS ? 'private entities: Map<string, THREE.Object3D> = new Map();' : ''}
  ${useTS ? 'private isPaused: boolean = false;' : ''}

  constructor(
    scene${useTS ? ': THREE.Scene' : ''}, 
    camera${useTS ? ': THREE.Camera' : ''}, 
    assetLoader${useTS ? ': AssetLoader' : ''},
    inputManager${useTS ? ': InputManager' : ''}
    ${hasPhysics ? `, world${useTS ? ': CANNON.World' : ''}` : ''}
  ) {
    this.scene = scene;
    this.camera = camera;
    this.assetLoader = assetLoader;
    this.input = inputManager;
    ${hasPhysics ? 'this.world = world;' : ''}
    ${useTS
            ? ''
            : `
    this.currentScene = null;
    this.entities = new Map();
    this.isPaused = false;`}
  }

  setCurrentScene(scene${useTS ? ': GameScene' : ''})${useTS ? ': void' : ''} {
    if (this.currentScene) {
      this.currentScene.destroy();
    }
    this.currentScene = scene;
  }

  registerEntity(id${useTS ? ': string' : ''}, entity${useTS ? ': THREE.Object3D' : ''})${useTS ? ': void' : ''} {
    this.entities.set(id, entity);
  }

  getEntity(id${useTS ? ': string' : ''})${useTS ? ': THREE.Object3D | undefined' : ''} {
    return this.entities.get(id);
  }

  update(delta${useTS ? ': number' : ''})${useTS ? ': void' : ''} {
    if (this.isPaused) return;
    
    if (this.currentScene) {
      this.currentScene.update(delta);
    }
  }

  pause()${useTS ? ': void' : ''} {
    this.isPaused = true;
  }

  resume()${useTS ? ': void' : ''} {
    this.isPaused = false;
  }

  get paused()${useTS ? ': boolean' : ''} {
    return this.isPaused;
  }

  // Utility methods
  raycast(origin${useTS ? ': THREE.Vector3' : ''}, direction${useTS ? ': THREE.Vector3' : ''})${useTS ? ': THREE.Intersection | null' : ''} {
    const raycaster = new THREE.Raycaster(origin, direction);
    const intersects = raycaster.intersectObjects(this.scene.children, true);
    return intersects.length > 0 ? intersects[0] : null;
  }

  getMouseWorldPosition(screenX${useTS ? ': number' : ''}, screenY${useTS ? ': number' : ''}, plane${useTS ? '?: THREE.Plane' : ''})${useTS ? ': THREE.Vector3 | null' : ''} {
    const mouse = new THREE.Vector2(
      (screenX / window.innerWidth) * 2 - 1,
      -(screenY / window.innerHeight) * 2 + 1
    );
    
    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, this.camera ${useTS ? 'as THREE.PerspectiveCamera' : ''});
    
    if (plane) {
      const target = new THREE.Vector3();
      raycaster.ray.intersectPlane(plane, target);
      return target;
    }
    
    const intersects = raycaster.intersectObjects(this.scene.children, true);
    return intersects.length > 0 ? intersects[0].point : null;
  }
}
`;
        this.addTextFile(`src/game/GameManager.${ext}`, gameManager);
        // AssetLoader
        const assetLoader = `import * as THREE from 'three';
import { GLTFLoader${useTS ? ', GLTF' : ''} } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

export class AssetLoader {
  ${useTS ? 'private textureLoader: THREE.TextureLoader;' : ''}
  ${useTS ? 'private gltfLoader: GLTFLoader;' : ''}
  ${useTS ? 'private audioLoader: THREE.AudioLoader;' : ''}
  ${useTS ? 'private textures: Map<string, THREE.Texture> = new Map();' : ''}
  ${useTS ? 'private models: Map<string, GLTF> = new Map();' : ''}
  ${useTS ? 'private audio: Map<string, AudioBuffer> = new Map();' : ''}

  constructor() {
    this.textureLoader = new THREE.TextureLoader();
    
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
    
    this.gltfLoader = new GLTFLoader();
    this.gltfLoader.setDRACOLoader(dracoLoader);
    
    this.audioLoader = new THREE.AudioLoader();
    
    ${useTS
            ? ''
            : `
    this.textures = new Map();
    this.models = new Map();
    this.audio = new Map();`}
  }

  async loadAll(onProgress${useTS ? '?: (progress: number) => void' : ''})${useTS ? ': Promise<void>' : ''} {
    // Load all assets here
    // This would be populated based on project assets
    if (onProgress) onProgress(1);
  }

  async loadTexture(path${useTS ? ': string' : ''})${useTS ? ': Promise<THREE.Texture>' : ''} {
    if (this.textures.has(path)) {
      return this.textures.get(path)${useTS ? '!' : ''};
    }

    return new Promise((resolve, reject) => {
      this.textureLoader.load(
        path,
        (texture) => {
          this.textures.set(path, texture);
          resolve(texture);
        },
        undefined,
        reject
      );
    });
  }

  async loadModel(path${useTS ? ': string' : ''})${useTS ? ': Promise<GLTF>' : ''} {
    if (this.models.has(path)) {
      return this.models.get(path)${useTS ? '!' : ''};
    }

    return new Promise((resolve, reject) => {
      this.gltfLoader.load(
        path,
        (gltf) => {
          this.models.set(path, gltf);
          resolve(gltf);
        },
        undefined,
        reject
      );
    });
  }

  getTexture(path${useTS ? ': string' : ''})${useTS ? ': THREE.Texture | undefined' : ''} {
    return this.textures.get(path);
  }

  getModel(path${useTS ? ': string' : ''})${useTS ? ': Promise<GLTF>' : ''} {
    return this.loadModel(path);
  }

  getAudio(path${useTS ? ': string' : ''})${useTS ? ': AudioBuffer | undefined' : ''} {
    return this.audio.get(path);
  }
}
`;
        this.addTextFile(`src/game/AssetLoader.${ext}`, assetLoader);
        // InputManager
        const inputManager = `import * as THREE from 'three';

export class InputManager {
  ${useTS ? 'private keys: Set<string> = new Set();' : ''}
  ${useTS ? 'private keysJustPressed: Set<string> = new Set();' : ''}
  ${useTS ? 'private keysJustReleased: Set<string> = new Set();' : ''}
  ${useTS ? 'private mousePosition: THREE.Vector2 = new THREE.Vector2();' : ''}
  ${useTS ? 'private mouseButtons: Set<number> = new Set();' : ''}
  ${useTS ? 'private mouseDelta: THREE.Vector2 = new THREE.Vector2();' : ''}
  ${useTS ? 'private wheelDelta: number = 0;' : ''}

  constructor() {
    ${useTS
            ? ''
            : `
    this.keys = new Set();
    this.keysJustPressed = new Set();
    this.keysJustReleased = new Set();
    this.mousePosition = new THREE.Vector2();
    this.mouseButtons = new Set();
    this.mouseDelta = new THREE.Vector2();
    this.wheelDelta = 0;`}
    
    window.addEventListener('keydown', this.onKeyDown.bind(this));
    window.addEventListener('keyup', this.onKeyUp.bind(this));
    window.addEventListener('mousemove', this.onMouseMove.bind(this));
    window.addEventListener('mousedown', this.onMouseDown.bind(this));
    window.addEventListener('mouseup', this.onMouseUp.bind(this));
    window.addEventListener('wheel', this.onWheel.bind(this));
    window.addEventListener('contextmenu', (e) => e.preventDefault());
  }

  private onKeyDown(e${useTS ? ': KeyboardEvent' : ''})${useTS ? ': void' : ''} {
    if (!this.keys.has(e.code)) {
      this.keysJustPressed.add(e.code);
    }
    this.keys.add(e.code);
  }

  private onKeyUp(e${useTS ? ': KeyboardEvent' : ''})${useTS ? ': void' : ''} {
    this.keys.delete(e.code);
    this.keysJustReleased.add(e.code);
  }

  private onMouseMove(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
    this.mouseDelta.set(e.movementX, e.movementY);
    this.mousePosition.set(e.clientX, e.clientY);
  }

  private onMouseDown(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
    this.mouseButtons.add(e.button);
  }

  private onMouseUp(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
    this.mouseButtons.delete(e.button);
  }

  private onWheel(e${useTS ? ': WheelEvent' : ''})${useTS ? ': void' : ''} {
    this.wheelDelta = e.deltaY;
  }

  isKeyPressed(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
    return this.keys.has(code);
  }

  isKeyJustPressed(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
    return this.keysJustPressed.has(code);
  }

  isKeyJustReleased(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
    return this.keysJustReleased.has(code);
  }

  isMouseButtonPressed(button${useTS ? ': number' : ''})${useTS ? ': boolean' : ''} {
    return this.mouseButtons.has(button);
  }

  getMousePosition()${useTS ? ': THREE.Vector2' : ''} {
    return this.mousePosition.clone();
  }

  getMouseDelta()${useTS ? ': THREE.Vector2' : ''} {
    return this.mouseDelta.clone();
  }

  getWheelDelta()${useTS ? ': number' : ''} {
    return this.wheelDelta;
  }

  getAxis(positive${useTS ? ': string' : ''}, negative${useTS ? ': string' : ''})${useTS ? ': number' : ''} {
    let value = 0;
    if (this.keys.has(positive)) value += 1;
    if (this.keys.has(negative)) value -= 1;
    return value;
  }

  update()${useTS ? ': void' : ''} {
    this.keysJustPressed.clear();
    this.keysJustReleased.clear();
    this.mouseDelta.set(0, 0);
    this.wheelDelta = 0;
  }
}
`;
        this.addTextFile(`src/game/InputManager.${ext}`, inputManager);
    }
    exportShaders(project) {
        var _a, _b, _c, _d;
        // Export shader assets
        const shaders = project.assets.filter((a) => a.type === 'shader');
        for (const shader of shaders) {
            const vertexShader = (_b = (_a = shader.metadata) === null || _a === void 0 ? void 0 : _a.vertex) !== null && _b !== void 0 ? _b : `
varying vec2 vUv;

void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}`;
            const fragmentShader = (_d = (_c = shader.metadata) === null || _c === void 0 ? void 0 : _c.fragment) !== null && _d !== void 0 ? _d : `
varying vec2 vUv;

void main() {
  gl_FragColor = vec4(vUv, 0.5, 1.0);
}`;
            this.addTextFile(`src/shaders/${this.sanitizeName(shader.name)}.vert`, vertexShader);
            this.addTextFile(`src/shaders/${this.sanitizeName(shader.name)}.frag`, fragmentShader);
        }
    }
    exportBundlerConfig(bundler, useTS) {
        if (bundler === 'vite') {
            this.addTextFile('vite.config.ts', `import { defineConfig } from 'vite';

export default defineConfig({
  base: './',
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: true,
  },
  server: {
    port: 3000,
    open: true,
  },
  assetsInclude: ['**/*.glb', '**/*.gltf', '**/*.hdr'],
});
`);
        }
        else if (bundler === 'webpack') {
            this.addTextFile('webpack.config.js', `const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/main.${useTS ? 'ts' : 'js'}',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.js'],
    alias: {
      'three/addons': path.resolve(__dirname, 'node_modules/three/examples/jsm'),
    },
  },
  module: {
    rules: [
      {
        test: /\\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\\.(glb|gltf|hdr)$/,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html',
    }),
  ],
  devServer: {
    static: './dist',
    port: 3000,
    open: true,
  },
};
`);
        }
    }
    exportTSConfig() {
        const tsconfig = {
            compilerOptions: {
                target: 'ES2020',
                useDefineForClassFields: true,
                module: 'ESNext',
                lib: ['ES2020', 'DOM', 'DOM.Iterable'],
                skipLibCheck: true,
                moduleResolution: 'bundler',
                allowImportingTsExtensions: true,
                resolveJsonModule: true,
                isolatedModules: true,
                noEmit: true,
                strict: true,
                noUnusedLocals: true,
                noUnusedParameters: true,
                noFallthroughCasesInSwitch: true,
                paths: {
                    'three/addons/*': ['node_modules/three/examples/jsm/*'],
                },
            },
            include: ['src'],
        };
        this.addTextFile('tsconfig.json', JSON.stringify(tsconfig, null, 2));
    }
    sanitizeName(name) {
        return name.replace(/[^a-zA-Z0-9]/g, '');
    }
}

exports.ThreeJSExporter = ThreeJSExporter;
//# sourceMappingURL=ThreeJSExporter.js.map
