/* ────────────────────────────────────────────────────────────────
   DeveloperExperience — LEGENDARY DX improvements
   
   Features:
   • Rich error messages with suggestions and docs links
   • API usage hints / auto-complete metadata
   • Performance dashboard data collection
   • Engine health check
   • Debug overlay system
──────────────────────────────────────────────────────────────── */
/** Error code registry with friendly messages */
const ERROR_REGISTRY = {
    'E001': {
        message: 'Entity not found',
        suggestion: 'Check that the entity ID exists. Use world.hasEntity(id) before accessing.',
        docsSection: 'ecs/entities',
        severity: 'error',
    },
    'E002': {
        message: 'Component not found on entity',
        suggestion: 'Use world.hasComponent(entityId, type) to check before getComponent().',
        docsSection: 'ecs/components',
        severity: 'error',
    },
    'E003': {
        message: 'Scene not registered',
        suggestion: 'Register the scene with sceneManager.register(id, config) before loading it.',
        docsSection: 'scenes/management',
        severity: 'error',
    },
    'E004': {
        message: 'Canvas not found',
        suggestion: 'Ensure the canvas element exists in the DOM before creating the engine. Use document.getElementById("your-canvas-id").',
        docsSection: 'getting-started',
        severity: 'error',
    },
    'E005': {
        message: 'Physics body has NaN values',
        suggestion: 'A velocity or position component has NaN. Check for division by zero or uninitialized values.',
        docsSection: 'physics/debugging',
        severity: 'error',
    },
    'E006': {
        message: 'Asset not loaded',
        suggestion: 'Load assets before using them: await assetManager.load(id, url). Check assetManager.isLoaded(id).',
        docsSection: 'assets/loading',
        severity: 'error',
    },
    'E007': {
        message: 'System priority conflict',
        suggestion: 'Two systems have the same priority. Assign unique priority values to control execution order.',
        docsSection: 'ecs/systems',
        severity: 'warning',
    },
    'E008': {
        message: 'Maximum entity count exceeded',
        suggestion: 'You have too many entities. Consider using object pooling (ObjectPool) or destroying unused entities.',
        docsSection: 'performance/pooling',
        severity: 'warning',
    },
    'E009': {
        message: 'Circular parent reference detected',
        suggestion: 'Entity A is a child of B which is a child of A. Remove the circular parent-child relationship.',
        docsSection: 'ecs/hierarchy',
        severity: 'error',
    },
    'E010': {
        message: 'WebGL context lost',
        suggestion: 'The browser lost the rendering context. This usually happens with GPU memory issues. Try reducing texture sizes.',
        docsSection: 'rendering/troubleshooting',
        severity: 'error',
    },
    'W001': {
        message: 'Frame time exceeds budget',
        suggestion: 'The frame took longer than 16.67ms (60 FPS). Profile your systems to find the bottleneck.',
        docsSection: 'performance/profiling',
        severity: 'warning',
    },
    'W002': {
        message: 'Orphaned event listener',
        suggestion: 'An event listener was registered but never unsubscribed. Store the unsubscribe function and call it in dispose().',
        docsSection: 'patterns/cleanup',
        severity: 'warning',
    },
    'W003': {
        message: 'Deprecated API usage',
        suggestion: 'This API is deprecated and will be removed in a future version. Check the migration guide.',
        docsSection: 'migration',
        severity: 'warning',
    },
    'W004': {
        message: 'Large texture detected',
        suggestion: 'Texture exceeds 2048x2048. Consider using texture atlases or lower resolution for better performance.',
        docsSection: 'assets/optimization',
        severity: 'warning',
    },
    'I001': {
        message: 'Engine initialized successfully',
        suggestion: '',
        docsSection: 'getting-started',
        severity: 'info',
    },
    'I002': {
        message: 'Hot module replacement active',
        suggestion: 'Changes to game scripts will be applied without restarting the engine.',
        docsSection: 'development/hmr',
        severity: 'info',
    },
};
/** Get a rich engine error by code */
function getEngineError(code, context) {
    const entry = ERROR_REGISTRY[code];
    if (!entry) {
        return {
            code,
            message: `Unknown engine error: ${code}`,
            suggestion: 'Report this issue at github.com/nicetdev/game-engine/issues',
            severity: 'error',
            context,
        };
    }
    return { code, ...entry, context };
}
/** Format an engine error for console output */
function formatEngineError(err) {
    const icon = err.severity === 'error' ? '❌' : err.severity === 'warning' ? '⚠️' : 'ℹ️';
    const lines = [
        `${icon} [Nice2Dev ${err.code}] ${err.message}`,
    ];
    if (err.suggestion) {
        lines.push(`   💡 ${err.suggestion}`);
    }
    if (err.docsSection) {
        lines.push(`   📖 Docs: https://nice2dev.com/docs/game-engine/${err.docsSection}`);
    }
    if (err.context) {
        lines.push(`   📋 Context: ${JSON.stringify(err.context)}`);
    }
    return lines.join('\n');
}
/** Throw a rich engine error */
function throwEngineError(code, context) {
    const err = getEngineError(code, context);
    throw new Error(formatEngineError(err));
}
/** Log a rich engine warning */
function warnEngine(code, context) {
    const err = getEngineError(code, context);
    // eslint-disable-next-line no-console
    console.warn(formatEngineError(err));
}
/** Core API hints for auto-complete and intellisense */
const API_HINTS = [
    {
        method: 'world.createEntity',
        module: 'ECS',
        signature: 'world.createEntity(name?: string): EntityId',
        description: 'Create a new entity in the world',
        example: 'const player = world.createEntity("Player");',
        params: [{ name: 'name', type: 'string', description: 'Optional display name', optional: true }],
        returns: 'EntityId — unique numeric ID',
        since: '0.1.0',
        tags: ['ecs', 'entity', 'create'],
    },
    {
        method: 'world.addComponent',
        module: 'ECS',
        signature: 'world.addComponent<K>(entityId, type: K, data?: Partial<ComponentMap[K]>): ComponentMap[K]',
        description: 'Add a component to an entity',
        example: 'world.addComponent(player, "Transform", { x: 100, y: 200 });',
        params: [
            { name: 'entityId', type: 'EntityId', description: 'Entity to add component to' },
            { name: 'type', type: 'string', description: 'Component type name (e.g., "Transform", "Sprite")' },
            { name: 'data', type: 'Partial<ComponentMap[K]>', description: 'Initial component data', optional: true },
        ],
        returns: 'The created component instance',
        since: '0.1.0',
        tags: ['ecs', 'component', 'add'],
    },
    {
        method: 'world.getComponent',
        module: 'ECS',
        signature: 'world.getComponent<K>(entityId, type: K): ComponentMap[K]',
        description: 'Get a component from an entity',
        example: 'const pos = world.getComponent(player, "Transform");',
        params: [
            { name: 'entityId', type: 'EntityId', description: 'Entity to get from' },
            { name: 'type', type: 'string', description: 'Component type name' },
        ],
        returns: 'The component data',
        since: '0.1.0',
        tags: ['ecs', 'component', 'get'],
    },
    {
        method: 'world.query',
        module: 'ECS',
        signature: 'world.query(...types: string[]): EntityId[]',
        description: 'Find all entities with ALL specified components',
        example: 'const movers = world.query("Transform", "RigidBody2D");',
        params: [
            { name: 'types', type: '...string[]', description: 'Component types to match (spread)' },
        ],
        returns: 'Array of matching EntityIds',
        since: '0.1.0',
        tags: ['ecs', 'query', 'search'],
    },
    {
        method: 'engine.start',
        module: 'Engine',
        signature: 'engine.start(): void',
        description: 'Start the game loop',
        example: 'engine.start();',
        params: [],
        returns: 'void',
        since: '0.1.0',
        tags: ['engine', 'start', 'loop'],
    },
    {
        method: 'input.isKeyDown',
        module: 'Input',
        signature: 'input.isKeyDown(key: string): boolean',
        description: 'Check if a key is currently held down (continuous)',
        example: 'if (input.isKeyDown("ArrowRight")) { /* move */ }',
        params: [{ name: 'key', type: 'string', description: 'Key code (e.g., "ArrowLeft", "Space", "KeyA")' }],
        returns: 'boolean',
        since: '0.1.0',
        tags: ['input', 'keyboard', 'continuous'],
    },
    {
        method: 'input.isKeyPressed',
        module: 'Input',
        signature: 'input.isKeyPressed(key: string): boolean',
        description: 'Check if a key was just pressed this frame (single-frame)',
        example: 'if (input.isKeyPressed("Space")) { /* jump */ }',
        params: [{ name: 'key', type: 'string', description: 'Key code' }],
        returns: 'boolean — true only on the first frame',
        since: '0.1.0',
        tags: ['input', 'keyboard', 'single-frame'],
    },
    {
        method: 'sceneManager.loadScene',
        module: 'Scene',
        signature: 'sceneManager.loadScene(id: string, transition?: TransitionType): void',
        description: 'Load a registered scene with optional transition',
        example: 'sceneManager.loadScene("level2", "fade");',
        params: [
            { name: 'id', type: 'string', description: 'Scene ID' },
            { name: 'transition', type: 'TransitionType', description: 'Transition effect', optional: true },
        ],
        returns: 'void',
        since: '0.1.0',
        tags: ['scene', 'load', 'transition'],
    },
];
/** Search API hints */
function searchAPIHints(query) {
    const lower = query.toLowerCase();
    return API_HINTS.filter(h => h.method.toLowerCase().includes(lower) ||
        h.description.toLowerCase().includes(lower) ||
        h.tags.some(t => t.includes(lower)));
}
function createPerfDashboard(maxSnapshots = 300) {
    return { snapshots: [], maxSnapshots, warnings: [] };
}
function recordPerfSnapshot(dashboard, snapshot) {
    dashboard.snapshots.push(snapshot);
    if (dashboard.snapshots.length > dashboard.maxSnapshots) {
        dashboard.snapshots.shift();
    }
    // Auto-detect warnings
    if (snapshot.fps < 30) {
        dashboard.warnings.push(`Low FPS: ${snapshot.fps.toFixed(1)} at ${new Date(snapshot.timestamp).toISOString()}`);
    }
    if (snapshot.frameTimeMs > 33) {
        dashboard.warnings.push(`Frame time spike: ${snapshot.frameTimeMs.toFixed(1)}ms`);
    }
    if (snapshot.entityCount > 5000) {
        dashboard.warnings.push(`High entity count: ${snapshot.entityCount}`);
    }
    // Keep last 50 warnings
    if (dashboard.warnings.length > 50) {
        dashboard.warnings.splice(0, dashboard.warnings.length - 50);
    }
}
/** Get average FPS from last N snapshots */
function getAverageFPS(dashboard, lastN = 60) {
    const snapshots = dashboard.snapshots;
    const start = Math.max(0, snapshots.length - lastN);
    const slice = snapshots.slice(start);
    if (slice.length === 0)
        return 0;
    let sum = 0;
    for (const s of slice)
        sum += s.fps;
    return sum / slice.length;
}
/** Get performance summary */
function getPerfSummary(dashboard) {
    const snaps = dashboard.snapshots;
    if (snaps.length === 0) {
        return { avgFPS: 0, minFPS: 0, maxFPS: 0, avgFrameTime: 0, peakFrameTime: 0, totalWarnings: 0 };
    }
    let sumFPS = 0;
    let minFPS = Infinity;
    let maxFPS = 0;
    let sumFrameTime = 0;
    let peakFrameTime = 0;
    for (const s of snaps) {
        sumFPS += s.fps;
        sumFrameTime += s.frameTimeMs;
        if (s.fps < minFPS)
            minFPS = s.fps;
        if (s.fps > maxFPS)
            maxFPS = s.fps;
        if (s.frameTimeMs > peakFrameTime)
            peakFrameTime = s.frameTimeMs;
    }
    return {
        avgFPS: sumFPS / snaps.length,
        minFPS,
        maxFPS,
        avgFrameTime: sumFrameTime / snaps.length,
        peakFrameTime,
        totalWarnings: dashboard.warnings.length,
    };
}
/** Run a health check on common engine misconfigurations */
function runHealthCheck(config) {
    const results = [];
    // Canvas size check
    if (config.canvasWidth > 3840 || config.canvasHeight > 2160) {
        results.push({
            category: 'Rendering',
            status: 'warning',
            message: 'Canvas resolution is very high',
            details: `${config.canvasWidth}x${config.canvasHeight} — may cause performance issues on lower-end devices.`,
        });
    }
    else {
        results.push({ category: 'Rendering', status: 'ok', message: 'Canvas resolution is reasonable' });
    }
    // Entity count
    if (config.entityCount > 10000) {
        results.push({
            category: 'ECS',
            status: 'error',
            message: 'Very high entity count',
            details: `${config.entityCount} entities. Consider object pooling or culling.`,
        });
    }
    else if (config.entityCount > 5000) {
        results.push({
            category: 'ECS',
            status: 'warning',
            message: 'High entity count',
            details: `${config.entityCount} entities. Monitor FPS closely.`,
        });
    }
    else {
        results.push({ category: 'ECS', status: 'ok', message: `${config.entityCount} entities — healthy` });
    }
    // FPS target
    if (config.targetFps > 144) {
        results.push({
            category: 'Performance',
            status: 'warning',
            message: 'Target FPS is unusually high',
            details: `${config.targetFps} FPS target. Most displays are 60-144Hz.`,
        });
    }
    else {
        results.push({ category: 'Performance', status: 'ok', message: `Target FPS: ${config.targetFps}` });
    }
    // Physics timestep
    if (config.physicsTimestep < 1 / 120) {
        results.push({
            category: 'Physics',
            status: 'warning',
            message: 'Physics timestep is very small',
            details: `${config.physicsTimestep.toFixed(6)}s — will use more CPU. Standard is 1/60.`,
        });
    }
    else {
        results.push({ category: 'Physics', status: 'ok', message: 'Physics timestep is standard' });
    }
    // Systems
    if (config.systemCount === 0) {
        results.push({
            category: 'ECS',
            status: 'warning',
            message: 'No systems registered',
            details: 'Add systems to process game logic.',
        });
    }
    else {
        results.push({ category: 'ECS', status: 'ok', message: `${config.systemCount} systems registered` });
    }
    // Texture
    if (config.maxTextureDimension > 4096) {
        results.push({
            category: 'Assets',
            status: 'warning',
            message: 'Large textures detected',
            details: `Max dimension: ${config.maxTextureDimension}px. Consider texture atlasing.`,
        });
    }
    else {
        results.push({ category: 'Assets', status: 'ok', message: 'Texture sizes are reasonable' });
    }
    return results;
}
const DEFAULT_DEBUG_OVERLAY = {
    showFPS: true,
    showEntityCount: true,
    showDrawCalls: false,
    showPhysicsDebug: false,
    showGrid: false,
    gridSize: 32,
    showBoundingBoxes: false,
    showOrigins: false,
    position: 'top-left',
    opacity: 0.85,
};
/** Render a debug text overlay onto a canvas context */
function renderDebugOverlay(ctx, config, stats, canvasSize) {
    const lines = [];
    if (config.showFPS)
        lines.push(`FPS: ${stats.fps.toFixed(0)} (${stats.frameTimeMs.toFixed(1)}ms)`);
    if (config.showEntityCount)
        lines.push(`Entities: ${stats.entityCount}`);
    if (config.showDrawCalls)
        lines.push(`Draw Calls: ${stats.drawCalls}`);
    if (lines.length === 0)
        return;
    const lineHeight = 16;
    const padding = 6;
    const width = 180;
    const height = lines.length * lineHeight + padding * 2;
    // Position
    let x = padding;
    let y = padding;
    if (config.position === 'top-right')
        x = canvasSize.x - width - padding;
    if (config.position === 'bottom-left')
        y = canvasSize.y - height - padding;
    if (config.position === 'bottom-right') {
        x = canvasSize.x - width - padding;
        y = canvasSize.y - height - padding;
    }
    // Background
    ctx.save();
    ctx.globalAlpha = config.opacity;
    ctx.fillStyle = '#000';
    ctx.fillRect(x, y, width, height);
    ctx.globalAlpha = 1;
    // Text
    ctx.fillStyle = stats.fps < 30 ? '#ff4444' : stats.fps < 55 ? '#ffaa00' : '#44ff44';
    ctx.font = '12px monospace';
    ctx.textBaseline = 'top';
    for (let i = 0; i < lines.length; i++) {
        ctx.fillText(lines[i], x + padding, y + padding + i * lineHeight);
    }
    ctx.restore();
}
const QUICK_START_TEMPLATES = [
    {
        id: 'empty-project',
        name: 'Empty Project',
        description: 'A blank canvas to start from scratch',
        category: 'prototype',
        difficulty: 'beginner',
        tags: ['empty', 'starter'],
        code: `const engine = new NiceGameEngine({
  canvas: document.getElementById("game") as HTMLCanvasElement,
  settings: { width: 800, height: 600, targetFps: 60 },
});

engine.start();`,
    },
    {
        id: 'hello-world',
        name: 'Hello World',
        description: 'A rotating square to verify everything works',
        category: 'demo',
        difficulty: 'beginner',
        tags: ['hello', 'demo', 'beginner'],
        code: `const engine = new NiceGameEngine({
  canvas: document.getElementById("game") as HTMLCanvasElement,
});

const entity = engine.world.createEntity("Square");
engine.world.addComponent(entity, "Transform", { x: 400, y: 300 });
engine.world.addComponent(entity, "Sprite", {
  shape: "rect", width: 50, height: 50, color: "#00ff88",
});

// Rotate every frame
engine.events.on("engine:update", () => {
  const t = engine.world.getComponent(entity, "Transform");
  t.rotation += 2;
});

engine.start();`,
    },
    {
        id: 'platformer-starter',
        name: 'Platformer Starter',
        description: 'A basic platformer with player, ground, and gravity',
        category: 'game',
        difficulty: 'intermediate',
        tags: ['platformer', 'physics', '2d'],
        code: `const engine = new NiceGameEngine({
  canvas: document.getElementById("game") as HTMLCanvasElement,
  settings: {
    width: 800, height: 600, targetFps: 60,
    physics: { gravity: { x: 0, y: 980 } },
  },
});

// Player
const player = engine.world.createEntity("Player");
engine.world.addComponent(player, "Transform", { x: 400, y: 400 });
engine.world.addComponent(player, "Sprite", {
  shape: "rect", width: 32, height: 48, color: "#4488ff",
});
engine.world.addComponent(player, "RigidBody2D", { type: "dynamic" });
engine.world.addComponent(player, "Collider2D", {
  shape: "box", width: 32, height: 48,
});

// Ground
const ground = engine.world.createEntity("Ground");
engine.world.addComponent(ground, "Transform", { x: 400, y: 580 });
engine.world.addComponent(ground, "Sprite", {
  shape: "rect", width: 800, height: 40, color: "#44aa44",
});
engine.world.addComponent(ground, "RigidBody2D", { type: "static" });
engine.world.addComponent(ground, "Collider2D", {
  shape: "box", width: 800, height: 40,
});

engine.start();`,
    },
];

export { API_HINTS, DEFAULT_DEBUG_OVERLAY, QUICK_START_TEMPLATES, createPerfDashboard, formatEngineError, getAverageFPS, getEngineError, getPerfSummary, recordPerfSnapshot, renderDebugOverlay, runHealthCheck, searchAPIHints, throwEngineError, warnEngine };
//# sourceMappingURL=DeveloperExperience.js.map
