package menu;

import game.GameMap;
import openfl.Assets;
import openfl.display.Sprite;
import raycaster.Raycaster;

using Std;

enum MenuCameraMoveState {
	ROTATE;
	MOVE;
}

class BgMaze extends Sprite {
	var rc:Raycaster;

	var state:MenuCameraMoveState = ROTATE;

	var moveTimeTotal:Float = 1;
	var moveTime:Float = 0;

	var fromCellX:Int;
	var fromCellY:Int;

	var toCellX:Int;
	var toCellY:Int;

	var fromAngle:Float;
	var toAngle:Float;

	var dx:Null<Int> = null;
	var dy:Null<Int> = null;

	public function new() {
		super();
		rc = new Raycaster(32, 32, 90, GameMap.fromJson(Assets.getText('assets/levels/menu.json')));
		rc.camera.angle = 0;
		rc.camera.direction.setTo(1, 0);
		rc.camera.position.setTo(1.5, 1.5);
		rc.alpha = 0.3;

		addChild(rc);

		chooseNextCell();
	}

	function chooseNextCell() {
		fromCellX = rc.camera.position.x.int();
		fromCellY = rc.camera.position.y.int();

		fromAngle = rc.camera.angle;

		var selectedCell:{cellX:Int, cellY:Int} = null;

		if (dx != null && dy != null) {
			var tile = rc.map.getTile(fromCellX + dx, fromCellY + dy);

			if (tile != null && !tile.collision)
				selectedCell = {cellX: fromCellX + dx, cellY: fromCellY + dy};
		}

		if (selectedCell == null) {
			var availableCells:Array<{cellX:Int, cellY:Int}> = [
				{cellX: fromCellX - 1, cellY: fromCellY},
				{cellX: fromCellX + 1, cellY: fromCellY},
				{cellX: fromCellX, cellY: fromCellY + 1},
				{cellX: fromCellX, cellY: fromCellY - 1}
			].filter(f -> {
				var tile = rc.map.getTile(f.cellX, f.cellY);

				return tile != null && !tile.collision;
			});

			if (availableCells.length > 0) {
				var rnd = availableCells[Math.floor(Math.random() * availableCells.length)];
				selectedCell = {cellX: rnd.cellX, cellY: rnd.cellY};
			} else
				throw 'Dead end';
		}

		toCellX = selectedCell.cellX;
		toCellY = selectedCell.cellY;

		toAngle = Math.atan2(toCellY - fromCellY, toCellX - fromCellX);

		moveTime = 0;

		dx = toCellX - fromCellX;
		dy = toCellY - fromCellY;

		if (toAngle != fromAngle)
			state = ROTATE;
		else
			state = MOVE;
	}

	public function update(delta:Float) {
		switch (state) {
			case MOVE:
				if (moveTime < moveTimeTotal) {
					rc.camera.position.x = fromCellX + (toCellX - fromCellX) * (moveTime / moveTimeTotal) + 0.5;
					rc.camera.position.y = fromCellY + (toCellY - fromCellY) * (moveTime / moveTimeTotal) + 0.5;
				} else {
					rc.camera.position.setTo(toCellX + 0.5, toCellY + 0.5);
					chooseNextCell();
				}
			case ROTATE:
				if (moveTime < moveTimeTotal) {
					rc.camera.angle = fromAngle + (toAngle - fromAngle) * (moveTime / moveTimeTotal);
				} else {
					rc.camera.angle = toAngle;
					state = MOVE;
					moveTime = 0;
				}
		}

		moveTime = Math.min(moveTimeTotal, moveTime + delta);
	}

	public function render() {
		rc.render();
	}
}
