package;

import flixel.addons.util.FlxFSM;
import flixel.FlxSprite;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.math.FlxPoint;
import flixel.math.FlxVelocity;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.util.FlxColor;
import flixel.util.FlxCollision;
import flixel.util.FlxSpriteUtil;
import flixel.math.FlxMath;
import flixel.util.FlxPath;

/**
 * ...
 * @author Laboon
 */
class Enemy extends FlxSprite
{
	public var speed:Int = 100;
	public var idleTmr:Float; //время которое будет стоять
	public var moveTimer:Float; //время которое будет идти
	public var moveDir:Float; //направление движения
	public var seesPlayer:Bool = false; //видит ли игрока
	public var playerPos(default, null):FlxPoint;//последняя точка в которой враг видел игрока
	public var isPlayerHidden:Bool = false;//находится ли игрок в коробке
	public var fsm:FlxFSM<Enemy>; //состояния
	public var attackTimer:Float;//задержка при атаке
	public var canAttack:Bool;
	//public var seenPlayerLastTime(default, null):FlxPoint
	public var alarm:Bool = false;
	public var alarmTimer:Float = 0;//время, которое будет искать игрока после тревоги
	public var enemyPath:FlxPath;
	public var pathPoints:Array<FlxPoint>;
	public var flag:Bool = false; //в движении ли игрок
	public var isDisabled:Bool = false; //"отключен" ли скрепкой
	public var seenHiding:Bool = false;// видел ли как игрок прятался
	
	
	public function new(?X:Float=0, ?Y:Float=0)
	{
		super(X, Y);
		this.drag.x = this.drag.y = 1800;
		this.attackTimer = 0.9;
		this.idleTmr = 10;
		loadGraphic(AssetPaths.enemyCat_attack__png, true, 29, 30);
		setFacingFlip(FlxObject.LEFT, false, false);
        setFacingFlip(FlxObject.RIGHT, true, false);
		animation.add("down", [0, 1, 2, 1], 7, false);
		animation.add("leftRight", [3, 4, 5, 4], 7, false);
		animation.add("up", [6, 7, 8, 7], 7, false);
		animation.add("attackDown", [9, 10, 1], 6, false);
		animation.add("attackLeftRight", [11, 12, 4], 6, false);
		animation.add("attackUp", [13, 14, 7], 6, false);
		animation.add("disabledUp", [17], 0, false);
		animation.add("disabledDown", [15], 0, false);
		animation.add("disabledLeftRight", [16], 0, false);
		setSize(20, 20);
		offset.set(5, 5);
		
		
		fsm = new FlxFSM<Enemy>(this);
		fsm.transitions
			.add(Idle, Chase, Conditions.chase)
			.add(Chase, Idle, Conditions.idle)
			.add(Chase, Attack, Conditions.attack)
			.add(Attack, Chase, Conditions.chase)
			.add(Attack, Idle, Conditions.idle)
			.add(Chase, Seek, Conditions.seek)
			.add(Seek, Chase, Conditions.chase)
			.add(Seek, Idle, Conditions.idle)
			.add(Idle, Disabled, Conditions.disabled)
			.add(Seek, Disabled, Conditions.disabled)
			.start(Idle);
		idleTmr = 0;
		playerPos = FlxPoint.get();
	}
	
	override public function draw():Void  //отрисовка
    {
        if ((velocity.x != 0 || velocity.y != 0 ) && touching == FlxObject.NONE)
        {
            if (Math.abs(velocity.x) > Math.abs(velocity.y))
            {
                 if (velocity.x < 0)
				 {
                    facing = FlxObject.LEFT;
				 }
                 else
				 {
                    facing = FlxObject.RIGHT;
				 }
            }
            else
            {
                 if (velocity.y < 0)
				 {
                    facing = FlxObject.UP;
				 }
                 else
				 {
                    facing = FlxObject.DOWN;
				 }
            }
			if(!isDisabled)
            switch (facing)
            {
                 case FlxObject.LEFT, FlxObject.RIGHT:
                     animation.play("leftRight");
                 case FlxObject.UP:
                     animation.play("up");
                 case FlxObject.DOWN:
                     animation.play("down");
            }
        }
        super.draw();
	}

	override public function update(elapsed:Float):Void
	{
		fsm.update(elapsed);
		super.update(elapsed);
		if (this.attackTimer > 0)
			this.attackTimer -= FlxG.elapsed;
		
	}
	
}

class Conditions //условия для состояний
{
	public static function idle(Owner:Enemy):Bool //бродить
	{
		return !Owner.seesPlayer && !Owner.alarm && !Owner.isDisabled && Owner.alarmTimer <= 0;
	}
	public static function chase(Owner:Enemy):Bool //гнаться
	{
		return (Owner.seesPlayer && !Owner.isDisabled && !Owner.isPlayerHidden) || (Owner.seesPlayer && !Owner.isDisabled && Owner.seenHiding && Owner.isPlayerHidden);
	}
	public static function attack(Owner:Enemy):Bool //атаковать
	{
		return (FlxMath.distanceToPoint(Owner, Owner.playerPos) <= 25 && Owner.attackTimer <= 0 && !Owner.isPlayerHidden && Owner.seesPlayer && !Owner.isDisabled) || (FlxMath.distanceToPoint(Owner, Owner.playerPos) <= 40 && Owner.attackTimer <= 0 && Owner.seenHiding && Owner.isPlayerHidden && Owner.seesPlayer && !Owner.isDisabled);
	}
	public static function seek(Owner:Enemy):Bool //искать
	{
		return Owner.alarm && !Owner.seesPlayer && Owner.alarmTimer > 0 && !Owner.isDisabled;
	}
	public static function disabled(Owner:Enemy):Bool //искать
	{
		return Owner.isDisabled;
	}
}
	
class Idle extends FlxFSMState<Enemy> //бродить
{
	override public function update(elapsed:Float, owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		if(owner.idleTmr <= 0)
		{
			if (!owner.flag)
			{
				owner.moveDir = FlxG.random.int(0, 8) * 45;
				owner.moveTimer = 0.4;
			}
			if (owner.moveTimer > 0)
			{
				owner.moveTimer -= FlxG.elapsed;
				owner.velocity.set(owner.speed, 0);
				owner.velocity.rotate(FlxPoint.weak(), owner.moveDir);
				owner.flag = true;
			}
			else if(owner.moveTimer <= 0)
			{
				owner.flag = false;
				owner.idleTmr = 3;
			}
		}
		else 
		{
			owner.velocity.x = owner.velocity.y = 0;
			owner.moveDir = -1;
			owner.idleTmr -= FlxG.elapsed;
			owner.flag = false;
		}
	}
}

class Chase extends FlxFSMState<Enemy> //гнаться
{
	override public function update(elapsed:Float, owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		FlxVelocity.moveTowardsPoint(owner, owner.playerPos, Std.int(owner.speed));
		owner.canAttack = false;
		owner.alarm = true;
		owner.alarmTimer = 5;
	}
}

class Attack extends FlxFSMState<Enemy> //атаковать
{
	override public function enter(owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		owner.attackTimer = 1;
		owner.canAttack = true;
		if (owner.facing == FlxObject.DOWN)
		{
			owner.animation.play("attackDown", true);
		}
		if (owner.facing == FlxObject.LEFT || owner.facing == FlxObject.RIGHT)
		{
			owner.animation.play("attackLeftRight", true);
		}
		if (owner.facing == FlxObject.UP)
		{
			owner.animation.play("attackUp", true);
		}
	}
	override public function update(elapsed:Float, owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		if (owner.attackTimer <= 0.1)
			owner.attackTimer = 1;
	}
}

class Seek extends FlxFSMState<Enemy>
{
	override public function enter(owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		owner.alarmTimer = 5;
	}
	override public function update(elapsed:Float, owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		owner.alarmTimer -= elapsed; //уменьшаем время, которое ему осталось искать
		if (owner.alarmTimer >= 0)
		{
			if (FlxMath.distanceToPoint(owner, owner.playerPos) > 30) //если он далеко от последней точки, где видел игрока, переместиться ближе
			{
				FlxVelocity.moveTowardsPoint(owner, owner.playerPos, Std.int(owner.speed));
			}
			else //иначе он рядом с последней точкой, начать поиск
			{
				
			}
		}
		else owner.alarm = false;
	}
}

class Disabled extends FlxFSMState<Enemy> //"быть отключенным"
{
	override public function enter(owner:Enemy, fsm:FlxFSM<Enemy>):Void 
	{
		owner.velocity.x = owner.velocity.y = 0;
		owner.canAttack = false;
		switch(owner.facing)
		{
			case FlxObject.DOWN:
				owner.animation.play("disabledDown");
			case FlxObject.UP:
				owner.animation.play("disabledUp");
			case FlxObject.RIGHT, FlxObject.LEFT:
				owner.animation.play("disabledLeftRight");
		}
	}
}