import Phaser from "phaser";
import Graphics from "../assets/Graphics";
import FOVLayer from "../entities/FOVLayer";
import Map from "../entities/Map";
import { TileType } from "../entities/Tile";
import Level0 from "../../assets/level0.png";
import Level1 from "../../assets/level1.png";
import Level2 from "../../assets/level2.png";
import Level3 from "../../assets/level3.png";
import hit1 from "../../assets/Hit_Hurt.wav";
import hit2 from "../../assets/Hit_Hurt2.wav";
import hit3 from "../../assets/Hit_Hurt3.wav";
import hit4 from "../../assets/Hit_Hurt4.wav";
import hit5 from "../../assets/Hit_Hurt5.wav";
import dash1 from "../../assets/Powerup.wav";
import dash2 from "../../assets/Powerup2.wav";
import dash3 from "../../assets/Powerup3.wav";
import pickup from "../../assets/Pickup.wav";

export default class DungeonScene extends Phaser.Scene {
  lastX: number;
  lastY: number;
  player: Player | null;
  fov: FOVLayer | null;
  tilemap: Phaser.Tilemaps.Tilemap | null;
  cameraResizeNeeded: boolean;

  preload(): void {
	this.load.audio('dash1', dash1);
	this.load.audio('dash2', dash2);
	this.load.audio('dash3', dash3);
    this.load.audio('hit1', hit1);
	this.load.audio('hit2', hit2);
	this.load.audio('hit3', hit3);
	this.load.audio('hit4', hit4);
	this.load.audio('hit5', hit5);
	this.load.audio('pickup', pickup);
	
	var levels = [Level0, Level1, Level2, Level3];
	var level = +location.search.substring(1);
	if (level < 0 || level > levels.length-1) {
		level = 0;
	}
	this.level = level;
	window.level = level;
	this.load.image("Level", levels[level]);
    this.load.image(Graphics.environment.name, Graphics.environment.file);
    this.load.image(Graphics.util.name, Graphics.util.file);
    this.load.spritesheet(Graphics.player.name, Graphics.player.file, {
      frameHeight: Graphics.player.height,
      frameWidth: Graphics.player.width
    });
    this.load.spritesheet(Graphics.slime.name, Graphics.slime.file, {
      frameHeight: Graphics.slime.height,
      frameWidth: Graphics.slime.width
    });
	this.load.spritesheet(Graphics.professor.name, Graphics.professor.file, {
      frameHeight: Graphics.professor.height,
      frameWidth: Graphics.professor.width
    });
	this.load.spritesheet(Graphics.items.name, Graphics.items.file, {
      frameHeight: Graphics.items.height,
      frameWidth: Graphics.items.width
    });
  }

  constructor() {
    super("DungeonScene");
    this.lastX = -1;
    this.lastY = -1;
    this.player = null;
    this.slime = null;
    this.fov = null;
    this.tilemap = null;
    this.cameraResizeNeeded = false;
  }

  create(): void {
	window.openDoors = [];
	window.openDoor = function(tile, wall, map) {
		if (tile.collides) {
			window.openDoors.push([wall.x, wall.y]);
			tile.collides = false;
			if (wall.index === 0x81) {
				wall.index = 0x91;
			} else if (wall.index === 0x82) {
				wall.index = 0x92;
			} else if (wall.index === 0x80) {
				wall.index = 0x73;
				map.doorLayerUp.putTileAt(0xb0, tile.x, tile.y-1);
			} else if (wall.index === 0x90) {
				wall.index = 0x73;
				map.doorLayerDown.putTileAt(0xa0, tile.x, tile.y);
			} else {
				wall.index = 0x73;
			}
			wall.resetCollision();
		}
	};
  
	this.game.sound.volume = 0.1;
	var dashs = [
		this.game.sound.add('dash1', {volume: 0.5}),
		this.game.sound.add('dash2', {volume: 0.5}),
		this.game.sound.add('dash3', {volume: 0.5})
	];
	var hits = [
		this.game.sound.add('hit1', {volume: 0.5}),
		this.game.sound.add('hit2', {volume: 0.5}),
		this.game.sound.add('hit3', {volume: 0.5}),
		this.game.sound.add('hit4', {volume: 0.5}),
		this.game.sound.add('hit5', {volume: 0.5})
	];
    window.hit = {};
	window.hit.play = function() {
		var min = 0;
		var max = hits.length-1;
		hits[Math.floor(Math.random()*(max-min+1)+min)].play();
	};
	window.dash = {};
	window.dash.play = function() {
		var min = 0;
		var max = dashs.length-1;
		dashs[Math.floor(Math.random()*(max-min+1)+min)].play();
	};
	window.pickup = this.game.sound.add('pickup', {volume: 0.5});
  
    var map;
    Object.values(Graphics.player.animations).forEach(anim => {
      if (!this.anims.get(anim.name)) {
        this.anims.create({
          key: anim.name,
          frames: this.anims.generateFrameNumbers(Graphics.player.name, anim),
          frameRate: anim.frameRate,
          repeat: anim.repeat ? -1 : 0
        });
      }
    });

    Object.values(Graphics.slime.animations).forEach(anim => {
      if (!this.anims.get(anim.name)) {
        this.anims.create({
          key: anim.name,
          frames: this.anims.generateFrameNumbers(Graphics.slime.name, anim),
          frameRate: anim.frameRate,
          repeat: anim.repeat ? -1 : 0
        });
      }
    });
	
	Object.values(Graphics.professor.animations).forEach(anim => {
      if (!this.anims.get(anim.name)) {
        this.anims.create({
          key: anim.name,
          frames: this.anims.generateFrameNumbers(Graphics.professor.name, anim),
          frameRate: anim.frameRate,
          repeat: anim.repeat ? -1 : 0
        });
      }
    });
	
	Object.values(Graphics.items.animations).forEach(anim => {
      if (!this.anims.get(anim.name)) {
        this.anims.create({
          key: anim.name,
          frames: this.anims.generateFrameNumbers(Graphics.items.name, anim),
          frameRate: anim.frameRate,
          repeat: anim.repeat ? -1 : 0
        });
      }
    });
	
    map = new Map(this);
	this.map = map;
	this.player = window.player;
    this.tilemap = map.tilemap;

    this.fov = new FOVLayer(map);

    this.cameras.main.setRoundPixels(true);
    this.cameras.main.setZoom(3);
    this.cameras.main.setBounds(
      0,
      0,
      map.width * Graphics.environment.width,
      map.height * Graphics.environment.height
    );
    this.cameras.main.startFollow(this.player.sprite);

    this.physics.add.collider(this.player.sprite, map.wallLayer, null, function(a, b) {
		var wall = this.player.sprite === a ? b : a;
		var tile = map.tiles[wall.y][wall.x];
		if (tile.tilecolor === window.nextLevel) {
			window.saveGame();
			localStorage.direction = 'forward';
			location.search = "?" + (this.level + 1);
			return true;
		}
		if (tile.tilecolor === window.lastLevel) {
			window.saveGame();
			localStorage.direction = 'backward';
			location.search = "?" + (this.level - 1);
			return true;
		}
		if (tile.type === TileType.Door) {
			window.openDoor(tile, wall, map);
			return false;
		}
		return true;
	}, this);
	for (var i = 0; i < window.enemy1.length; ++i) {
		this.physics.add.collider(window.enemy1[i].sprite, map.wallLayer);
	}
    window.addEventListener("resize", () => {
      this.cameraResizeNeeded = true;
    });

    this.input.keyboard.on("keydown_R", () => {
      if (window.confirm("Are you sure that you want to start a new game?")) {
		window.resetGame();
		location.search = "";
	  }
    });
	
	/*this.input.keyboard.on("keydown_T", () => {
      this.scene.stop("InfoScene");
      this.scene.start("ReferenceScene");
    });*/

    this.scene.run("InfoScene");
  }

  update(time: number, delta: number) {
	if (!window.paused) {
		this.player!.update(time);
		if (window.professor) {
			window.professor.update(time);
		}
		if (window.julina) {
			window.julina.update(time);
		}
		for (var i = 0; i < window.enemy1.length; ++i) {
			window.enemy1[i].update(this.fov, this.map, time);
		}
	} else {
		this.player.body.setVelocity(0);
		if (window.professor) {
			window.professor.body.setVelocity(0);
		}
		if (window.julina) {
			window.julina.body.setVelocity(0);
		}
		for (var i = 0; i < window.enemy1.length; ++i) {
			window.enemy1[i].body.setVelocity(0);
		}
	}
	
    const camera = this.cameras.main;

    if (this.cameraResizeNeeded) {
      camera.setSize(window.innerWidth, window.innerHeight);
      this.cameraResizeNeeded = false;
    }

    const player = new Phaser.Math.Vector2({
      x: this.tilemap!.worldToTileX(this.player!.sprite.body.x),
      y: this.tilemap!.worldToTileY(this.player!.sprite.body.y)
    });

    const bounds = new Phaser.Geom.Rectangle(
      this.tilemap!.worldToTileX(camera.worldView.x) - 1,
      this.tilemap!.worldToTileY(camera.worldView.y) - 1,
      this.tilemap!.worldToTileX(camera.worldView.width) + 2,
      this.tilemap!.worldToTileY(camera.worldView.height) + 2
    );

    this.fov!.update(player, bounds, delta);
  }
}
