using Otter;
using Puppyups.entities;
using Puppyups.scenes;
using Puppyups.Scenes;
using Puppyups.Utilities;
using System;

namespace Puppyups.objects
{
    class SmogMonster : 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 = 100f;//only if close do they come to you. it's a small space, i guess 100.
        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;
        public Grapple friendlyGrapple;
        public Grapple2 friendlyGrapple2;
        private bool one;
        private int StunTimer = 0;

        public bool Pulled;
        private bool oneSound = true;

        public SmogMonster(float x, float y)
        {
            X = x; Y = y;
            SetHitbox(50, 50, (int)Global.Type.SMOGMONSTER);
            Collider.X = -10;
            Collider.Y = -25;
            _spriteMap = new Spritemap<string>(Assets.SMOGMONSTER, 100, 100);
            _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;
            _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.DOG);
            movement.Axis.Locked = true;
            AddComponents(axis, movement, button);
            angleInRadians = GetAngle(Rand.Float(0f, 359f));
        }

        public override void Update()
        {
            base.Update();
            var player = Collider.Collide(X, Y, (int)Global.Type.PLAYER);
            if (player != null)
            {
                SoundManager.PlayRequestedSound("_death");
                Global.GAME.RemoveScene();
                Global.GAME.AddScene(new LoseScreen());
            }
            var player2 = Collider.Collide(X, Y, (int)Global.Type.PLAYER2);
            if (player2 != null)
            {
                SoundManager.PlayRequestedSound("_death");
                Global.GAME.RemoveScene();
                Global.GAME.AddScene(new LoseScreen());
            }
            if (_first)
            {
                _first = false;
                var wall = Collider.Collide(X, Y, (int)Global.Type.SOLID);
                if (wall != null)
                {
                    Destroy();
                    Scene.Add(new Dog(Rand.Float(64, Global.MW - 64), Rand.Float(64, Global.MH - 64)));
                }
            }
            //if (StunTimer > 0 && Pulled)
            //    StunTimer--;
            //if (StunTimer <= 0)
            //    Pulled = false;
            if (Pulled)
            {//this should just be set to the grapple location.Eh, lets see what happens. Lets set the grapple to this location. lol
                movement.SpeedScale = 50;
                movement.Freeze = false;
                movement.RemoveCollision((int)Global.Type.DOG);//remove the collision so we can get away.
                if (friendlyGrapple != null)
                {
                    X = friendlyGrapple.X - 1;
                    Y = friendlyGrapple.Y - 20;
                }
                else if (friendlyGrapple2 != null)
                {
                    X = friendlyGrapple2.X - 1;
                    Y = friendlyGrapple2.Y - 20;
                }
                Shared.ChangeAnimTo("stunned", _spriteMap);
                if (oneSound)
                {
                    oneSound = false;
                    var rand = Rand.Int(1, 4);
                    if (rand == 1)
                        SoundManager.PlayRequestedSound("_dogstun");
                    else if (rand == 2)
                        SoundManager.PlayRequestedSound("_dogstun1");
                    else if (rand == 3)
                        SoundManager.PlayRequestedSound("_dogstun2");
                }
                //StunTimer = 200;
            }
            else if (AmICollidingWithMyFriends(Collider) && first)
            {
                movement.RemoveCollision((int)Global.Type.DOG);//remove the collision so we can get away.
                if (Timer % 34 == 0)
                    angleInRadians = GetAngle(Rand.Float(0f, 359f));
                Global.dogSpeed = 1f;
                GetVelocity(angleInRadians);
                movement.Axis.ForceState(velocity);
            }
            else
            {
                movement.SpeedScale = 100;
                if (!movement.CollisionsSolid.Contains((int)Global.Type.DOG))//if there is not collision dog, add it.
                    movement.AddCollision((int)Global.Type.DOG);//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);
                    movement.Freeze = false;
                    if (AmICollidingWithMyFriends(Collider))
                    {
                        movement.RemoveCollision((int)Global.Type.DOG);//remove the collision so we can get away.
                        if (Timer % 34 == 0)
                            angleInRadians = GetAngle(Rand.Float(0f, 359f));
                        Global.dogSpeed = .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("_ringcollected", .2f);
                                }
                                break;
                            default://or 0.
                                Global.dogSpeed = .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);
                    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);
                    }
                    else
                    {
                        Shared.ChangeAnimTo("standLeft", _spriteMap);
                    }

                    standTimer--;
                }
                if (stand && standTimer <= 0)
                {
                    stand = false;
                    closestItem = null;
                    closestDistanceItem = 200f;
                    one = true;
                    isTimeToMove = true;
                }
                if (_amIMovingLeft && !stand)
                {
                    Shared.ChangeAnimTo("walkLeft", _spriteMap);
                }
                if (_amIMovingRight && !stand)
                {
                    Shared.ChangeAnimTo("walkRight", _spriteMap);
                }
                //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

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

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

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

            var anyPlayer2 = GetEntities<Player2>();
            foreach (var item in anyPlayer2)
            {
                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();
            base.Render();
        }

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

        public void Destroy()
        {
            RemoveSelf();
        }
    }
}

