/**
 * Spatial Creator Toolkit Templates
 * TypeScript templates for building VR/AR experiences on Spatial
 */

import { ScriptTemplate } from './templates';

export const spatialTemplates: ScriptTemplate[] = [
  {
    id: 'spatial-hello-world',
    name: 'Hello World',
    description: 'Basic Spatial script to log messages and interact with the world',
    category: 'beginner',
    platform: 'spatial',
    code: `import { SpatialEngine } from '@spatialos/spatial-sdk';

// Initialize Spatial engine
const engine = new SpatialEngine();

// Log hello message
console.log('Hello from Spatial!');
console.log('Welcome to VR/AR development!');

// Example: Access the world
engine.onReady(() => {
  console.log('Spatial world is ready!');
  console.log('Player count:', engine.world.players.length);
});`,
  },
  {
    id: 'spatial-player-tracker',
    name: 'Player Join Handler',
    description: 'Detect when players join and leave the Spatial world',
    category: 'beginner',
    platform: 'spatial',
    code: `import { SpatialEngine, Player } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Track player joins
engine.world.onPlayerJoin.subscribe((player: Player) => {
  console.log(\`Player joined: \${player.displayName}\`);
  console.log(\`Player ID: \${player.id}\`);
  console.log(\`Total players: \${engine.world.players.length}\`);

  // Welcome message
  player.sendMessage('Welcome to the experience!');
});

// Track player leaves
engine.world.onPlayerLeave.subscribe((player: Player) => {
  console.log(\`Player left: \${player.displayName}\`);
  console.log(\`Remaining players: \${engine.world.players.length}\`);
});`,
  },
  {
    id: 'spatial-object-interaction',
    name: 'Object Interaction',
    description: 'Handle clicks and interactions with 3D objects',
    category: 'ui',
    platform: 'spatial',
    code: `import { SpatialEngine, GameObject, InteractionEvent } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Get reference to interactive object
const interactiveObject = engine.world.findObject('InteractiveButton');

if (interactiveObject) {
  // Add click handler
  interactiveObject.onInteract.subscribe((event: InteractionEvent) => {
    console.log('Object clicked!');
    console.log('Player:', event.player.displayName);

    // Change object color on interaction
    interactiveObject.setColor('#00FF00');

    // Send feedback to player
    event.player.sendMessage('Button activated!');

    // Reset after 1 second
    setTimeout(() => {
      interactiveObject.setColor('#FFFFFF');
    }, 1000);
  });
}`,
  },
  {
    id: 'spatial-countdown-timer',
    name: 'Countdown Timer',
    description: 'Create a countdown timer with UI updates',
    category: 'gameplay',
    platform: 'spatial',
    code: `import { SpatialEngine, UIElement } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Timer configuration
const countdownSeconds = 60;
let timeRemaining = countdownSeconds;

// Create UI text element for timer
const timerUI = engine.ui.createTextElement({
  text: \`Time: \${timeRemaining}s\`,
  position: { x: 0.5, y: 0.9 }, // Top center
  fontSize: 24,
  color: '#FFFFFF',
});

// Countdown function
const startCountdown = async () => {
  console.log(\`Timer starting: \${countdownSeconds} seconds\`);

  const interval = setInterval(() => {
    timeRemaining--;
    timerUI.setText(\`Time: \${timeRemaining}s\`);

    // Change color when time is running out
    if (timeRemaining <= 10) {
      timerUI.setColor('#FF0000'); // Red
    } else if (timeRemaining <= 30) {
      timerUI.setColor('#FFFF00'); // Yellow
    }

    console.log(\`Time remaining: \${timeRemaining}s\`);

    if (timeRemaining <= 0) {
      clearInterval(interval);
      onTimerComplete();
    }
  }, 1000);
};

const onTimerComplete = () => {
  console.log('Timer completed!');
  timerUI.setText('TIME UP!');

  // Notify all players
  engine.world.broadcastMessage('Timer has ended!');
};

// Start when world is ready
engine.onReady(() => {
  startCountdown();
});`,
  },
  {
    id: 'spatial-score-tracker',
    name: 'Score Tracker',
    description: 'Track and display player scores',
    category: 'gameplay',
    platform: 'spatial',
    code: `import { SpatialEngine, Player } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Score storage
const playerScores = new Map<string, number>();

// Initialize player score
const initializePlayer = (player: Player) => {
  playerScores.set(player.id, 0);
  updateScoreUI(player);
};

// Award points to player
const awardPoints = (player: Player, points: number) => {
  const currentScore = playerScores.get(player.id) || 0;
  const newScore = currentScore + points;

  playerScores.set(player.id, newScore);

  console.log(\`\${player.displayName} earned \${points} points\`);
  console.log(\`New score: \${newScore}\`);

  // Update UI
  updateScoreUI(player);

  // Send message to player
  player.sendMessage(\`+\${points} points! Total: \${newScore}\`);
};

// Update score UI for player
const updateScoreUI = (player: Player) => {
  const score = playerScores.get(player.id) || 0;

  // Create or update score UI element
  const scoreUI = engine.ui.createTextElement({
    text: \`Score: \${score}\`,
    position: { x: 0.1, y: 0.9 },
    fontSize: 18,
    color: '#FFD700', // Gold
    playerId: player.id, // Only visible to this player
  });
};

// Get player score
const getPlayerScore = (player: Player): number => {
  return playerScores.get(player.id) || 0;
};

// Get leaderboard
const getLeaderboard = (): Array<{ player: Player; score: number }> => {
  const leaderboard: Array<{ player: Player; score: number }> = [];

  playerScores.forEach((score, playerId) => {
    const player = engine.world.players.find(p => p.id === playerId);
    if (player) {
      leaderboard.push({ player, score });
    }
  });

  return leaderboard.sort((a, b) => b.score - a.score);
};

// Initialize all players
engine.world.onPlayerJoin.subscribe(initializePlayer);`,
  },
  {
    id: 'spatial-trigger-zone',
    name: 'Trigger Zone',
    description: 'Detect when players enter/exit trigger areas',
    category: 'gameplay',
    platform: 'spatial',
    code: `import { SpatialEngine, TriggerZone, Player } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Create trigger zone
const triggerZone = engine.world.createTriggerZone({
  position: { x: 0, y: 0, z: 0 },
  size: { x: 10, y: 5, z: 10 }, // 10x5x10 meter zone
  name: 'RewardZone',
});

// Track players in zone
const playersInZone = new Set<string>();

// Handle player entering zone
triggerZone.onEnter.subscribe((player: Player) => {
  console.log(\`\${player.displayName} entered trigger zone\`);

  playersInZone.add(player.id);

  // Grant reward
  player.sendMessage('You entered the reward zone!');

  // Example: Award points
  // awardPoints(player, 10);

  // Example: Spawn item
  // spawnItemForPlayer(player);
});

// Handle player exiting zone
triggerZone.onExit.subscribe((player: Player) => {
  console.log(\`\${player.displayName} exited trigger zone\`);

  playersInZone.delete(player.id);

  player.sendMessage('You left the reward zone');
});

// Check if player is in zone
const isPlayerInZone = (player: Player): boolean => {
  return playersInZone.has(player.id);
};

// Get all players in zone
const getPlayersInZone = (): Player[] => {
  return engine.world.players.filter(p => playersInZone.has(p.id));
};`,
  },
  {
    id: 'spatial-object-spawner',
    name: 'Object Spawner',
    description: 'Spawn objects at intervals or on demand',
    category: 'tools',
    platform: 'spatial',
    code: `import { SpatialEngine, GameObject, Vector3 } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Spawner configuration
const spawnInterval = 5000; // 5 seconds
const maxObjects = 10;

// Track spawned objects
const spawnedObjects: GameObject[] = [];

// Spawn an object at position
const spawnObject = (position: Vector3) => {
  // Check max limit
  if (spawnedObjects.length >= maxObjects) {
    console.log('Max objects reached, removing oldest');
    const oldest = spawnedObjects.shift();
    oldest?.destroy();
  }

  // Create new object
  const obj = engine.world.createObject({
    type: 'Cube',
    position: position,
    scale: { x: 1, y: 1, z: 1 },
    color: '#00FFFF',
  });

  spawnedObjects.push(obj);

  console.log(\`Spawned object at (\${position.x}, \${position.y}, \${position.z})\`);

  return obj;
};

// Auto-spawn at intervals
const startAutoSpawn = () => {
  setInterval(() => {
    // Random position
    const position = {
      x: Math.random() * 20 - 10, // -10 to 10
      y: 5,
      z: Math.random() * 20 - 10, // -10 to 10
    };

    spawnObject(position);
  }, spawnInterval);

  console.log('Auto-spawn started');
};

// Spawn at player position
const spawnAtPlayer = (player: Player) => {
  const position = player.getPosition();
  spawnObject(position);
};

// Clear all spawned objects
const clearAllObjects = () => {
  spawnedObjects.forEach(obj => obj.destroy());
  spawnedObjects.length = 0;
  console.log('All objects cleared');
};

// Start spawning when ready
engine.onReady(() => {
  startAutoSpawn();
});`,
  },
  {
    id: 'spatial-teleporter',
    name: 'Teleporter System',
    description: 'Teleport players to different locations',
    category: 'gameplay',
    platform: 'spatial',
    code: `import { SpatialEngine, Player, Vector3, GameObject } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Teleport destinations
const destinations = {
  spawn: { x: 0, y: 0, z: 0 },
  arena: { x: 50, y: 0, z: 50 },
  shop: { x: -30, y: 0, z: 20 },
  vault: { x: 0, y: 100, z: 0 },
};

// Teleport player to location
const teleportPlayer = (player: Player, destination: Vector3) => {
  console.log(\`Teleporting \${player.displayName} to \${JSON.stringify(destination)}\`);

  // Set player position
  player.setPosition(destination);

  // Send confirmation
  player.sendMessage(\`Teleported to (\${destination.x}, \${destination.y}, \${destination.z})\`);
};

// Teleport to named destination
const teleportToDestination = (player: Player, destinationName: keyof typeof destinations) => {
  const destination = destinations[destinationName];

  if (destination) {
    teleportPlayer(player, destination);
  } else {
    console.error(\`Unknown destination: \${destinationName}\`);
  }
};

// Create teleport pads
const createTeleportPad = (name: string, position: Vector3, destination: Vector3) => {
  const pad = engine.world.createObject({
    type: 'Cylinder',
    position: position,
    scale: { x: 2, y: 0.2, z: 2 },
    color: '#9900FF',
  });

  // Create trigger zone on pad
  const zone = engine.world.createTriggerZone({
    position: position,
    size: { x: 2, y: 1, z: 2 },
    name: \`TeleportPad_\${name}\`,
  });

  zone.onEnter.subscribe((player: Player) => {
    teleportPlayer(player, destination);
  });

  return { pad, zone };
};

// Example: Create teleport pads
engine.onReady(() => {
  createTeleportPad('ToArena', { x: 0, y: 0, z: 10 }, destinations.arena);
  createTeleportPad('ToShop', { x: 0, y: 0, z: -10 }, destinations.shop);
  createTeleportPad('ToVault', { x: 10, y: 0, z: 0 }, destinations.vault);

  console.log('Teleport pads created');
});`,
  },
  {
    id: 'spatial-animation-controller',
    name: 'Animation Controller',
    description: 'Control object animations and movements',
    category: 'advanced',
    platform: 'spatial',
    code: `import { SpatialEngine, GameObject, Vector3 } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Animation controller class
class AnimationController {
  private object: GameObject;
  private isAnimating: boolean = false;

  constructor(object: GameObject) {
    this.object = object;
  }

  // Rotate object continuously
  startRotation(speed: number = 1) {
    if (this.isAnimating) return;

    this.isAnimating = true;
    const rotateLoop = () => {
      if (!this.isAnimating) return;

      const currentRotation = this.object.getRotation();
      this.object.setRotation({
        x: currentRotation.x,
        y: currentRotation.y + speed,
        z: currentRotation.z,
      });

      requestAnimationFrame(rotateLoop);
    };

    rotateLoop();
  }

  stopRotation() {
    this.isAnimating = false;
  }

  // Move object smoothly to target position
  async moveTo(target: Vector3, duration: number = 1000) {
    const start = this.object.getPosition();
    const startTime = Date.now();

    return new Promise<void>((resolve) => {
      const animate = () => {
        const elapsed = Date.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);

        // Ease in-out function
        const eased = progress < 0.5
          ? 2 * progress * progress
          : -1 + (4 - 2 * progress) * progress;

        // Interpolate position
        const current = {
          x: start.x + (target.x - start.x) * eased,
          y: start.y + (target.y - start.y) * eased,
          z: start.z + (target.z - start.z) * eased,
        };

        this.object.setPosition(current);

        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          resolve();
        }
      };

      animate();
    });
  }

  // Scale animation (pulse effect)
  async pulse(scaleFactor: number = 1.5, duration: number = 500) {
    const originalScale = this.object.getScale();

    await this.scaleTo(
      {
        x: originalScale.x * scaleFactor,
        y: originalScale.y * scaleFactor,
        z: originalScale.z * scaleFactor,
      },
      duration / 2
    );

    await this.scaleTo(originalScale, duration / 2);
  }

  // Scale to target size
  async scaleTo(target: Vector3, duration: number = 500) {
    const start = this.object.getScale();
    const startTime = Date.now();

    return new Promise<void>((resolve) => {
      const animate = () => {
        const elapsed = Date.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);

        const current = {
          x: start.x + (target.x - start.x) * progress,
          y: start.y + (target.y - start.y) * progress,
          z: start.z + (target.z - start.z) * progress,
        };

        this.object.setScale(current);

        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          resolve();
        }
      };

      animate();
    });
  }
}

// Example usage
engine.onReady(() => {
  const obj = engine.world.findObject('AnimatedCube');

  if (obj) {
    const controller = new AnimationController(obj);

    // Start rotation
    controller.startRotation(2);

    // Pulse every 3 seconds
    setInterval(() => {
      controller.pulse(1.3, 600);
    }, 3000);
  }
});`,
  },
  {
    id: 'spatial-voice-zone',
    name: 'Voice Chat Zone',
    description: 'Create proximity-based voice chat areas',
    category: 'ui',
    platform: 'spatial',
    code: `import { SpatialEngine, Player, VoiceZone } from '@spatialos/spatial-sdk';

const engine = new SpatialEngine();

// Create voice chat zone
const createVoiceZone = (
  name: string,
  position: Vector3,
  radius: number,
  isPrivate: boolean = false
) => {
  const zone = engine.world.createVoiceZone({
    name: name,
    position: position,
    radius: radius,
    isPrivate: isPrivate,
    volumeFalloff: 'linear', // or 'exponential'
  });

  console.log(\`Created voice zone: \${name}\`);

  // Track players in zone
  const playersInZone = new Set<string>();

  zone.onPlayerEnter.subscribe((player: Player) => {
    playersInZone.add(player.id);
    console.log(\`\${player.displayName} entered voice zone: \${name}\`);

    player.sendMessage(\`Entered voice zone: \${name}\`);
  });

  zone.onPlayerLeave.subscribe((player: Player) => {
    playersInZone.delete(player.id);
    console.log(\`\${player.displayName} left voice zone: \${name}\`);

    player.sendMessage(\`Left voice zone: \${name}\`);
  });

  return {
    zone,
    getPlayerCount: () => playersInZone.size,
    getPlayers: () => Array.from(playersInZone),
  };
};

// Example: Create multiple voice zones
engine.onReady(() => {
  // Public zone in main area
  createVoiceZone(
    'MainHall',
    { x: 0, y: 0, z: 0 },
    20, // 20 meter radius
    false // Public
  );

  // Private zone for meetings
  createVoiceZone(
    'MeetingRoom',
    { x: 30, y: 0, z: 30 },
    10, // 10 meter radius
    true // Private (invite only)
  );

  // Stage area with larger radius
  createVoiceZone(
    'Stage',
    { x: 0, y: 0, z: 50 },
    30, // 30 meter radius
    false
  );

  console.log('Voice zones created');
});`,
  },
];
