import { ISpawnPoint } from "../interfaces/ISpawnPoint";
import { ItemSpawnPoint } from "./ItemSpawnPoint";
import { CharacterSpawnPoint } from "./CharacterSpawnPoint";
import { EnemySpawnPoint } from "./EnemySpawnPoint";
import { World } from "../world/World";
import { LoadingManager } from "../core/LoadingManager";
import { EventType } from "../enums/EventType";
import {
  ScenarioProps,
  ModelProps,
  DataType,
  ModelType,
  DriverType,
} from "../enums/WorldType";

export class Scenario {
  public id: string;
  public name: string;
  public world: World;
  private spawnPoints: ISpawnPoint[] = [];
  private initialCameraAngle: number;
  private enemies: number = 0;

  constructor(root: THREE.Object3D, world: World) {
    this.world = world;
    this.id = root.name;

    // Scenario
    if (root.hasOwnProperty(ModelProps.USER_DATA)) {
      const rootUserData = root[ModelProps.USER_DATA];
      if (rootUserData.hasOwnProperty(ScenarioProps.NAME)) {
        this.name = rootUserData.name;
      }
      if (rootUserData.hasOwnProperty(ScenarioProps.CAMERA_ANGLE)) {
        this.initialCameraAngle = rootUserData[ScenarioProps.CAMERA_ANGLE];
      }
    }

    // Find all scenario spawns and entities
    root.traverse((child) => {
      if (child.hasOwnProperty(ModelProps.USER_DATA)) {
        const userData = child[ModelProps.USER_DATA];
        if (userData[DataType.DATA_PROP] === DataType.SPAWN) {
          if (userData[ModelType.MODEL_PROP] === ModelType.SHARD) {
            const sp = new ItemSpawnPoint(child);
            this.spawnPoints.push(sp);
          } 
          if (
            userData[ModelType.MODEL_PROP] === ModelType.ENEMY &&
            userData.hasOwnProperty(DriverType.DRIVER_PROP)
          ) {
            this.enemies += 1;
            const sp = new EnemySpawnPoint(child);
            sp.driver = userData[DriverType.DRIVER_PROP];
            this.spawnPoints.push(sp);
          }
          if (userData[ModelType.MODEL_PROP] === ModelType.PLAYER) {
            const sp = new CharacterSpawnPoint(child);
            this.spawnPoints.push(sp);
          }
        }
      }
    });
  }

  public launch(loadingManager: LoadingManager, world: World): void {
    if (this.enemies > 0) {
      this.world.triggerEvent({
        type: EventType.ENEMIES,
        targets: [`${this.enemies}`],
      });
    }

    this.spawnPoints.forEach((sp) => {
      sp.spawn(loadingManager, world);
    });

    world.cameraOperator.theta = this.initialCameraAngle;
    world.cameraOperator.phi = 15;
  }

  public destroy(): void {
    for (let i = 0; i < this.spawnPoints.length; i++) {
      this.spawnPoints[i].destroy();
    }
    this.spawnPoints = undefined;
    this.id = undefined;
    this.name = undefined;
    this.world = undefined;
    this.initialCameraAngle = undefined;
    this.enemies = undefined;
  }
}
