import * as BABYLON from '@babylonjs/core';
import { Network } from './network';
import { Player } from './player';
import { Weapons } from './weapons';
import { UI } from './ui';

export class Game {
  private engine: BABYLON.Engine | null = null;
  private scene: BABYLON.Scene | null = null;
  private camera: BABYLON.UniversalCamera | null = null;
  private network: Network | null = null;
  private localPlayer: Player | null = null;
  private opponents: Map<string, Player> = new Map();
  private weapons: Weapons | null = null;
  private ui: UI | null = null;
  private playerName: string = '';
  private isGameRunning: boolean = false;

  async init() {
    // Initialize Babylon.js
    const canvas = document.getElementById('gameContainer') as HTMLCanvasElement;
    this.engine = new BABYLON.Engine(canvas, true);
    this.scene = new BABYLON.Scene(this.engine);
    this.scene.collisionsEnabled = true;

    // Create camera (first-person view)
    this.camera = new BABYLON.UniversalCamera('camera', new BABYLON.Vector3(0, 1.6, 0), this.scene);
    this.camera.attachControl(canvas, true);
    this.camera.inertia = 0.7;
    this.camera.speed = 0;
    this.camera.angularSensibility = 1000;
    this.camera.checkCollisions = true;

    // Lighting
    const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), this.scene);
    light.intensity = 0.8;
    const sunLight = new BABYLON.PointLight('sun', new BABYLON.Vector3(10, 20, 10), this.scene);
    sunLight.intensity = 0.5;

    // Create arena (basic)
    this.createArena();

    // Initialize game systems
    this.weapons = new Weapons(this.scene);
    this.ui = new UI();
    this.network = new Network(this);

    // Render loop
    this.engine.runRenderLoop(() => {
      if (this.isGameRunning && this.localPlayer) {
        this.localPlayer.update(this.camera!);
      }
      this.scene!.render();
    });

    // Resize listener
    window.addEventListener('resize', () => {
      this.engine?.resize();
    });

    this.ui.updateStatus('Ready to play');
    this.ui.showMenu(true);
  }

  private createArena() {
    // Ground
    const ground = BABYLON.MeshBuilder.CreateGround('ground', { width: 50, height: 50 }, this.scene!);
    const groundMat = new BABYLON.StandardMaterial('groundMat', this.scene!);
    groundMat.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
    ground.material = groundMat;
    ground.checkCollisions = true;

    // Walls
    const walls = [
      { pos: new BABYLON.Vector3(-25, 5, 0), size: new BABYLON.Vector3(1, 10, 50) }, // Left
      { pos: new BABYLON.Vector3(25, 5, 0), size: new BABYLON.Vector3(1, 10, 50) }, // Right
      { pos: new BABYLON.Vector3(0, 5, -25), size: new BABYLON.Vector3(50, 10, 1) }, // Back
      { pos: new BABYLON.Vector3(0, 5, 25), size: new BABYLON.Vector3(50, 10, 1) }, // Front
    ];

    const wallMat = new BABYLON.StandardMaterial('wallMat', this.scene!);
    wallMat.emissiveColor = new BABYLON.Color3(0.3, 0.3, 0.3);

    walls.forEach((wall, i) => {
      const wallMesh = BABYLON.MeshBuilder.CreateBox(`wall_${i}`, { size: 1 }, this.scene!);
      wallMesh.position = wall.pos;
      wallMesh.scaling = wall.size;
      wallMesh.material = wallMat;
      wallMesh.checkCollisions = true;
    });

    // Obstacles (pillars)
    const pillars = [
      new BABYLON.Vector3(-10, 3, -10),
      new BABYLON.Vector3(10, 3, 10),
      new BABYLON.Vector3(-10, 3, 10),
      new BABYLON.Vector3(10, 3, -10),
    ];

    const pillarMat = new BABYLON.StandardMaterial('pillarMat', this.scene!);
    pillarMat.emissiveColor = new BABYLON.Color3(0.6, 0.2, 0.2);

    pillars.forEach((pos, i) => {
      const pillar = BABYLON.MeshBuilder.CreateCylinder(`pillar_${i}`, { diameter: 2, height: 6 }, this.scene!);
      pillar.position = pos;
      pillar.material = pillarMat;
      pillar.checkCollisions = true;
    });
  }

  joinMatchmaking() {
    const playerNameInput = document.getElementById('playerNameInput') as HTMLInputElement;
    this.playerName = playerNameInput.value.trim() || `Player_${Math.random().toString(36).slice(2, 8)}`;

    this.ui?.showMenu(false);
    this.ui?.updateStatus('Looking for opponent...');

    if (this.network) {
      this.network.joinMatchmaking(this.playerName);
    }
  }

  startMatch(matchData: any) {
    console.log('Starting match:', matchData);
    this.isGameRunning = true;

    // Create local player
    this.localPlayer = new Player(
      this.camera!,
      this.scene!,
      matchData.player1.username === this.playerName
        ? matchData.player1
        : matchData.player2,
      true
    );

    // Create opponent player
    const opponentData = matchData.player1.username === this.playerName ? matchData.player2 : matchData.player1;
    const opponent = new Player(this.camera!, this.scene!, opponentData, false);
    this.opponents.set(opponentData.id, opponent);

    this.ui?.showHUD(true);
    this.ui?.updateOpponentName(opponentData.username);

    // Send initial position
    if (this.network) {
      this.network.sendPlayerUpdate(this.localPlayer.getState());
    }
  }

  updateRemotePlayer(playerId: string, state: any) {
    const opponent = this.opponents.get(playerId);
    if (opponent) {
      opponent.setRemoteState(state);
    }
  }

  fireWeapon(position: BABYLON.Vector3, direction: BABYLON.Vector3) {
    if (!this.localPlayer) return;

    const weapon = this.weapons?.getWeapon(this.localPlayer.currentWeapon);
    if (!weapon) return;

    // Client-side hit detection
    const hit = this.raycastHit(position, direction);

    if (this.network) {
      this.network.sendShot(position, direction, this.localPlayer.currentWeapon);
    }

    if (hit) {
      this.ui?.showHitMarker();
      if (this.network) {
        this.network.sendHitRegistered(hit.playerId, weapon.damage);
      }
    }
  }

  private raycastHit(position: BABYLON.Vector3, direction: BABYLON.Vector3): { playerId: string } | null {
    const hit = this.scene?.pickWithRay(
      new BABYLON.Ray(position, direction, 100),
      (mesh) => {
        // Check if hit is an opponent
        for (const [playerId, opponent] of this.opponents) {
          if (opponent.getMesh().id === mesh.id) {
            return true;
          }
        }
        return false;
      }
    );

    if (hit?.hit) {
      // Find which opponent was hit
      for (const [playerId, opponent] of this.opponents) {
        if (opponent.getMesh().id === hit.pickedMesh?.id) {
          return { playerId };
        }
      }
    }

    return null;
  }

  endMatch(winner: string) {
    this.isGameRunning = false;
    this.ui?.showMenu(true);
    alert(`Match ended! ${winner} won!`);
  }

  getScene(): BABYLON.Scene {
    return this.scene!;
  }

  getCamera(): BABYLON.UniversalCamera {
    return this.camera!;
  }

  getLocalPlayer(): Player | null {
    return this.localPlayer;
  }
}
