using LOoSE_sLOTS.objects;
using LOoSE_sLOTS.Utilities;
using Otter;
using System;

namespace LOoSE_sLOTS.entities
{
    class Civilian : Entity
    {
        private Spritemap<string> _spriteMap;
        private BasicMovement movement = new BasicMovement(1600, 1600, 1600);
        private bool isTimeToMove = true;
        private bool stand = false;
        private int rand = 0;
        private int walkTimer = 0;
        private int standTimer = 0;
        private bool _amIMovingLeft = false;
        private bool _amIMovingRight = false;
        private Button button = new Button();
        private float _forcedSpeed = 2f;//this is the decend rate to position. was 1
        //scanning!
        private float closestDistanceItem = 50f;//only if close do they come to you. it's a small space, i guess 100. (remember this setting is below too)
        private Entity closestItem;
        private double angleInRadians = 1;//this is about 57 degrees. ;-)
        private double reverseAngleInRadians = 1;
        private float angleInFrisbees = 1;
        private bool first = true;
        private bool _first = true;
        private Vector2 velocity = new Vector2(.3f, .3f);//this is the x and y speeds.
        private float _X;
        private float _Y;
        private bool one;
        private bool isInHall = false;

        private bool oneSound = true;
        public int Health = 2;
        private float _scale;

        public Civilian(float x, float y)
        {
            X = x; Y = y;
            SetHitbox(8, 12, (int)Global.Type.CIVILIAN);
            Collider.X = -5;
            Collider.Y = 0;
            _spriteMap = new Spritemap<string>(Assets.CIVILIAN, 50, 50);
            _spriteMap.Add("standRight", new int[] { 0, 1 }, new float[] { 7f, 7f });//defaults to right
            _spriteMap.Add("standLeft", new int[] { 0, 1 }, new float[] { 7f, 7f });//be sure to flip the spritemap before you use this.
            _spriteMap.Add("walkRight", new int[] { 0, 1 }, new float[] { 7f, 7f });
            _spriteMap.Add("walkLeft", new int[] { 0, 1 }, new float[] { 7f, 7f });//all left has to be flipped.
            _spriteMap.Add("stunned", new int[] { 2 }, new float[] { 5f, 5f });
            _spriteMap.Play("standLeft");
            _spriteMap.Color = Color.Random;
            _scale = Rand.Float(.7f, 1.5f);//cool but need to scale collider with this. :/
            _spriteMap.Scale = _scale;
            _spriteMap.CenterOrigin();
            Graphic = _spriteMap;
            Layer = 1;

            //normal walk
            Axis axis = new Axis();
            movement.Axis = axis;
            movement.Axis.AddKeys(Key.P, Key.O, Key.I, Key.U);
            movement.Collider = Collider;
            movement.SpeedScale = 100;//normal speed
            movement.AddCollision((int)Global.Type.SOLID, (int)Global.Type.CIVILIAN);
            movement.Axis.Locked = true;
            AddComponents(axis, movement, button);
            angleInRadians = GetAngle(Rand.Float(0f, 359f));
        }

        public override void Update()
        {
            base.Update();            
            if (AmICollidingWithMyFriends(Collider) && first)
            {
                movement.RemoveCollision((int)Global.Type.CIVILIAN);//remove the collision so we can get away.
                if (Timer % 34 == 0)
                    angleInRadians = GetAngle(Rand.Float(0f, 359f));
                Global.civilianSpeed = 1f;
                GetVelocity(angleInRadians);
                movement.Axis.ForceState(velocity);
            }
            else
            {
                movement.SpeedScale = 100;
                if (!movement.CollisionsSolid.Contains((int)Global.Type.CIVILIAN))//if there is not collision dog, add it.
                    movement.AddCollision((int)Global.Type.CIVILIAN);//walls
                first = false;
                if (isTimeToMove)
                {//basic movement with interactions and states.
                    isTimeToMove = false;
                    walkTimer = Rand.Int(100, 150);
                    _forcedSpeed = Rand.Float(.005f, .03f);
                    rand = ScanAllTargets();
                }
                if (walkTimer > 0)
                {
                    walkTimer--;
                    //Console.WriteLine("rand: {0} (1 up, 2 rightup, 3 right, 4 downright, 5 down, 6 downleft, 7 left, 8 upleft 9 yawn, 0 randomdirection", rand);
                    if (isInHall)
                        movement.Freeze = true;
                    else
                        movement.Freeze = false;
                    if (AmICollidingWithMyFriends(Collider))
                    {
                        movement.RemoveCollision((int)Global.Type.CIVILIAN);//remove the collision so we can get away.
                        if (Timer % 34 == 0)
                            angleInRadians = GetAngle(Rand.Float(0f, 359f));
                        Global.civilianSpeed = .2f;
                        GetVelocity(angleInRadians);
                        movement.Axis.ForceState(velocity);
                    }
                    else
                    {
                        switch (rand)
                        {//why don't we just grab a random angle and try to walk in that direction?
                            case (int)Move.up:
                                movement.Axis.ForceState(0, -_forcedSpeed);
                                _amIMovingRight = true;
                                _amIMovingLeft = false;
                                break;
                            case (int)Move.upRight:
                                movement.Axis.ForceState(_forcedSpeed, -_forcedSpeed);
                                _amIMovingRight = true;
                                _amIMovingLeft = false;
                                break;
                            case (int)Move.right:
                                movement.Axis.ForceState(_forcedSpeed, 0);
                                _amIMovingRight = true;
                                _amIMovingLeft = false;
                                break;
                            case (int)Move.downRight:
                                movement.Axis.ForceState(_forcedSpeed, _forcedSpeed);
                                _amIMovingRight = true;
                                _amIMovingLeft = false;
                                break;
                            case (int)Move.down:
                                movement.Axis.ForceState(0, _forcedSpeed);
                                _amIMovingRight = false;
                                _amIMovingLeft = true;
                                break;
                            case (int)Move.downLeft:
                                movement.Axis.ForceState(-_forcedSpeed, _forcedSpeed);
                                _amIMovingRight = false;
                                _amIMovingLeft = true;
                                break;
                            case (int)Move.left:
                                movement.Axis.ForceState(-_forcedSpeed, 0);
                                _amIMovingRight = false;
                                _amIMovingLeft = true;
                                break;
                            case (int)Move.upLeft:
                                movement.Axis.ForceState(-_forcedSpeed, -_forcedSpeed);
                                _amIMovingRight = false;
                                _amIMovingLeft = true;
                                break;
                            case (int)Move.yawn:
                                //Console.WriteLine("need to implement yawn?");
                                if (one)
                                {
                                    one = false;
                                    //SoundManager.PlayRequestedSound("_giveMeMoney", .2f);
                                }
                                break;
                            default://or 0.
                                Global.civilianSpeed = .1f;
                                GetVelocity(angleInRadians);
                                movement.Axis.ForceState(velocity);
                                if (angleInFrisbees > 0 && angleInFrisbees <= 90 || angleInFrisbees > 270 && angleInFrisbees <= 360)
                                {
                                    _amIMovingRight = true;
                                    _amIMovingLeft = false;
                                }
                                else
                                {
                                    _amIMovingRight = false;
                                    _amIMovingLeft = true;
                                }
                                break;
                        }
                    }
                }
                if (!stand && walkTimer <= 0)
                {
                    stand = true;
                    movement.Axis.ReleaseState();
                    movement.Freeze = true;
                    //Shared.ChangeAnimTo("standLeft", _spriteMap);
                    _spriteMap.FlippedX = true;
                    if (closestItem != null)
                        standTimer = Rand.Int(60, 161);
                    // Console.WriteLine("stand: {0}", stand);
                    //Console.WriteLine("stand timer: {0}", standTimer);
                }
                if (stand && standTimer > 0)
                {
                    if (_amIMovingRight)
                    {
                        Shared.ChangeAnimTo("standRight", _spriteMap);
                        _spriteMap.FlippedX = false;
                    }
                    else
                    {
                        Shared.ChangeAnimTo("standLeft", _spriteMap);
                        _spriteMap.FlippedX = true;
                    }

                    standTimer--;
                }
                if (stand && standTimer <= 0)
                {
                    //SoundManager.PlayRequestedSound(RandomYip(), .08f); MAYBE random statement
                    stand = false;
                    closestItem = null;
                    closestDistanceItem = 50f;
                    one = true;
                    isTimeToMove = true;
                }
                if (_amIMovingLeft && !stand)
                {
                    Shared.ChangeAnimTo("walkLeft", _spriteMap);
                    _spriteMap.FlippedX = true;
                }
                if (_amIMovingRight && !stand)
                {
                    Shared.ChangeAnimTo("walkRight", _spriteMap);
                    _spriteMap.FlippedX = false;
                }
                //map edges
                var offset = 24;
                if (X < -offset)
                    X = Global.MW - 9;
                else if (X > Global.MW - 9)
                    X = -offset;
                if (Y < -offset)
                    Y = Global.MH - 9;
                else if (Y > Global.MH - 9)
                    Y = -offset;
            }
        }//end of update

        private string RandomDeathSound()
        {
            switch (Rand.Int(1, 16))//one more than the last
            {
                case 1:
                    return "_dead";
                case 2:
                    return "_dead2";
                case 3:
                    return "_dead3";
                case 4:
                    return "_dead4";
                case 5:
                    return "_dead5";
                case 6:
                    return "_dead6";
                case 7:
                    return "_dead7";
                case 8:
                    return "_dead8";
                case 9:
                    return "_dead9";
                case 10:
                    return "_dead10";
                case 11:
                    return "_dead11";
                case 12:
                    return "_dead12";
                case 13:
                    return "_dead13";
                case 14:
                    return "_dead14";
                default:
                    return "_dead";
            }
        }

        public bool AmICollidingWithMyFriends(Collider c)
        {
            var dog = c.Collide(X, Y, (int)Global.Type.CIVILIAN);
            if (dog != null)
                return true;
            else
                return false;
        }

        private void GetVelocity(double originalAngle)//these speeds are not variable enough. :/
        {
            _X = Global.civilianSpeed * (float)Math.Cos(originalAngle);
            _Y = Global.civilianSpeed * (float)Math.Sin(originalAngle);
            velocity = new Vector2(_X, _Y);
        }

        public int ScanAllTargets()
        {
            var anyCoins = GetEntities<GameCoin>();
            foreach (var item in anyCoins)
            {
                var dist = Util.Distance(this, item);
                if (dist <= closestDistanceItem)
                {
                    closestDistanceItem = dist;
                    closestItem = item;
                }
            }

            var anyPlayer = GetEntities<Player>();
            foreach (var item in anyPlayer)
            {
                var dist = Util.Distance(this, item);
                if (dist <= closestDistanceItem)
                {
                    closestDistanceItem = dist;
                    closestItem = item;
                }
            }

            var anySniper = GetEntities<Sniper>();
            foreach (var item in anySniper)
            {
                var dist = Util.Distance(this, item);
                if (dist <= closestDistanceItem)
                {
                    closestDistanceItem = dist;
                    closestItem = item;
                }
            }
            if (closestItem != null)
                return GetClosestDirection();
            else
                return GetRandomNumber();
        }

        public int GetClosestDirection()//this will return an angle to go there. or itshould have...
        {
            if (closestItem != null)
            {
                var vector1 = new Point((int)closestItem.X, (int)closestItem.Y);
                var vector2 = new Point((int)X, (int)Y);
                angleInRadians = Math.Atan2(vector2.Y - vector1.Y, vector2.X - vector1.X);
                angleInFrisbees = MathHelper.ToDegrees((float)angleInRadians);
                //var player = GetEntity<Player>();
                //var distX = player.X - X;
                //var distY = Math.Abs(player.Y - Y);
                if (angleInFrisbees < 0)
                {
                    angleInFrisbees += 360;
                    //Console.WriteLine("angle: {0}", angleInFrisbees);
                    angleInRadians = MathHelper.ToRadians(angleInFrisbees);
                }
                return 0;
            }
            else
                return GetRandomNumber();
        }

        public void GetDirection(int destX, int destY, int sourceX, int sourceY)
        {
            var vector1 = new Point(sourceX, sourceY);
            var vector2 = new Point(destX, destY);
            angleInRadians = Math.Atan2(vector2.Y - vector1.Y, vector2.X - vector1.X);
            var angleInFrisbees = MathHelper.ToDegrees((float)angleInRadians);
            if (angleInFrisbees < 0)
            {
                angleInFrisbees += 360;
                angleInRadians = MathHelper.ToRadians(angleInFrisbees);
            }
        }

        public int GetRandomNumber()
        {
            //Console.WriteLine("getting a random number because no one is close enough. xD");
            angleInRadians = MathHelper.ToRadians(Rand.Angle);//grab a random angle!
            return Rand.Int(1, 10);
        }

        private enum Move
        {
            nothing,
            up,
            upRight,
            right,
            downRight,
            down,
            downLeft,
            left,
            upLeft,
            yawn
        }

        public override void Render()
        {
            //Collider.Render(Color.Cyan);
            base.Render();
        }

        public double GetAngle(float angle)
        {
            var tempAngle = MathHelper.ToRadians(angle);
            reverseAngleInRadians = MathHelper.ToRadians(angle + 180);
            return tempAngle;
        }

        public void Destroy()
        {
            for (var i = 0; i < 3; i++)
            {
                Global.GAME.Scene.Add(new GameCoin(X, Y, Y + 12));
            }
            Global.CiviliansKilled++;
            Global.score--;
            SoundManager.PlayRequestedSound(RandomDeathSound(), .5f);
            Scene.Add(new DeadCivilian(X, Y, _spriteMap.Color, _scale));
            RemoveSelf();
        }
    }
}


