using System;
using Decimation.Content.Projectiles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;

namespace Decimation.Lib.Projectile
{
    public abstract class WormProjectile : DecimationProjectile
    {
        protected int BodyType;
        protected bool Directional = false;

        protected bool Flies = false;

        /* ai[0] = follower
		 * ai[1] = following
		 * ai[2] = distanceFromTail
		 * ai[3] = head
		 */
        protected bool Head;
        protected int HeadType;
        protected int MaxLength;
        protected int MinLength;
        protected float Speed;
        protected bool Tail;
        protected int TailType;

        protected float TurnSpeed;

        protected int Target;
        protected int RealLife;

        protected float DistanceFromTail;
        protected float WormHead;

        public override void AI()
        {
            if (projectile.localAI[1] == 0f)
            {
                projectile.localAI[1] = 1f;
                InitWorm();
            }

            if (WormHead > 0f) RealLife = (int) WormHead;

            if (!Head && projectile.timeLeft < 300) projectile.timeLeft = 300;
            if (Target < 0 || Target == 255 || !Main.npc[Target].active)
                TargetClosest();
            if (Main.player[projectile.owner].dead && projectile.timeLeft > 300) projectile.timeLeft = 300;

            Entity target;
            if (Target < 0)
            {
                target = Main.player[projectile.owner];
            }
            else
            {
                target = Main.npc[Target];
            }

            if (Main.netMode != 1)
            {
                if (!Tail && projectile.ai[0] == 0f)
                {
                    if (Head)
                    {
                        WormHead = projectile.whoAmI;
                        RealLife = projectile.whoAmI;
                        DistanceFromTail = Main.rand.Next(MinLength, MaxLength + 1);
                        projectile.ai[0] = Terraria.Projectile.NewProjectile(
                            (int) (projectile.position.X + projectile.width / 2f),
                            (int) (projectile.position.Y + projectile.height),
                            0f,
                            0f,
                            BodyType,
                            0,
                            0f,
                            projectile.owner
                        );
                    }
                    else if (DistanceFromTail > 0f)
                    {
                        projectile.ai[0] = Terraria.Projectile.NewProjectile(
                            (int) (projectile.position.X + projectile.width / 2f),
                            (int) (projectile.position.Y + projectile.height),
                            0f,
                            0f,
                            projectile.type,
                            0,
                            0f,
                            projectile.owner
                        );
                    }
                    else
                    {
                        projectile.ai[0] = Terraria.Projectile.NewProjectile(
                            (int) (projectile.position.X + projectile.width / 2f),
                            (int) (projectile.position.Y + projectile.height),
                            0f,
                            0f,
                            TailType,
                            0,
                            0f,
                            projectile.whoAmI
                        );
                    }

                    ((WormProjectile) Main.projectile[(int) projectile.ai[0]].modProjectile).WormHead = WormHead;
                    ((WormProjectile) Main.projectile[(int) projectile.ai[0]].modProjectile).RealLife = RealLife;
                    Main.projectile[(int) projectile.ai[0]].ai[1] = projectile.whoAmI;
                    ((WormProjectile) Main.projectile[(int) projectile.ai[0]].modProjectile).DistanceFromTail =
                        DistanceFromTail - 1f;
                    projectile.netUpdate = true;
                }
            }

            var num180 = (int) (projectile.position.X / 16f) - 1;
            var num181 = (int) ((projectile.position.X + projectile.width) / 16f) + 2;
            var num182 = (int) (projectile.position.Y / 16f) - 1;
            var num183 = (int) ((projectile.position.Y + projectile.height) / 16f) + 2;
            if (num180 < 0) num180 = 0;
            if (num181 > Main.maxTilesX) num181 = Main.maxTilesX;
            if (num182 < 0) num182 = 0;
            if (num183 > Main.maxTilesY) num183 = Main.maxTilesY;
            var flag18 = Flies;
            if (!flag18)
                for (var num184 = num180; num184 < num181; num184++)
                for (var num185 = num182; num185 < num183; num185++)
                    if (Main.tile[num184, num185] != null &&
                        (Main.tile[num184, num185].nactive() &&
                         (Main.tileSolid[Main.tile[num184, num185].type] ||
                          Main.tileSolidTop[Main.tile[num184, num185].type] && Main.tile[num184, num185].frameY == 0) ||
                         Main.tile[num184, num185].liquid > 64))
                    {
                        Vector2 vector17;
                        vector17.X = num184 * 16;
                        vector17.Y = num185 * 16;
                        if (projectile.position.X + projectile.width > vector17.X &&
                            projectile.position.X < vector17.X + 16f &&
                            projectile.position.Y + projectile.height > vector17.Y &&
                            projectile.position.Y < vector17.Y + 16f)
                        {
                            flag18 = true;
                        }
                    }

            if (!flag18 && Head)
            {
                var rectangle = new Rectangle((int) projectile.position.X, (int) projectile.position.Y,
                    projectile.width, projectile.height);
                var num186 = 1000;
                var flag19 = true;
                for (var num187 = 0; num187 < 255; num187++)
                    if (Main.player[num187].active)
                    {
                        var rectangle2 = new Rectangle((int) Main.player[num187].position.X - num186,
                            (int) Main.player[num187].position.Y - num186, num186 * 2, num186 * 2);
                        if (rectangle.Intersects(rectangle2))
                        {
                            flag19 = false;
                            break;
                        }
                    }

                if (flag19) flag18 = true;
            }

            if (Directional)
            {
                if (projectile.velocity.X < 0f)
                    projectile.spriteDirection = 1;
                else if (projectile.velocity.X > 0f) projectile.spriteDirection = -1;
            }

            var num188 = Speed;
            var num189 = TurnSpeed;
            var vector18 = new Vector2(projectile.position.X + projectile.width * 0.5f,
                projectile.position.Y + projectile.height * 0.5f);
            var num191 = target.position.X + target.width / 2f;
            var num192 = target.position.Y + target.height / 2f;

            num191 = (int) (num191 / 16f) * 16;
            num192 = (int) (num192 / 16f) * 16;
            vector18.X = (int) (vector18.X / 16f) * 16;
            vector18.Y = (int) (vector18.Y / 16f) * 16;
            num191 -= vector18.X;
            num192 -= vector18.Y;
            var num193 = (float) Math.Sqrt(num191 * num191 + num192 * num192);
            if (projectile.ai[1] > 0f && projectile.ai[1] < Main.projectile.Length)
            {
                try
                {
                    vector18 = new Vector2(projectile.position.X + projectile.width * 0.5f,
                        projectile.position.Y + projectile.height * 0.5f);
                    num191 = Main.projectile[(int) projectile.ai[1]].position.X +
                             Main.projectile[(int) projectile.ai[1]].width / 2 -
                             vector18.X;
                    num192 = Main.projectile[(int) projectile.ai[1]].position.Y +
                             Main.projectile[(int) projectile.ai[1]].height / 2 -
                             vector18.Y;
                }
                catch
                {
                }

                projectile.rotation = (float) Math.Atan2(num192, num191) + 1.57f;
                num193 = (float) Math.Sqrt(num191 * num191 + num192 * num192);
                int num194 = projectile.width;
                num193 = (num193 - num194) / num193;
                num191 *= num193;
                num192 *= num193;
                projectile.velocity = Vector2.Zero;
                projectile.position.X = projectile.position.X + num191;
                projectile.position.Y = projectile.position.Y + num192;
                if (Directional)
                {
                    if (num191 < 0f) projectile.spriteDirection = 1;
                    if (num191 > 0f) projectile.spriteDirection = -1;
                }
            }
            else
            {
                if (!flag18)
                {
                    TargetClosest();
                    projectile.velocity.Y = projectile.velocity.Y + 0.11f;
                    if (projectile.velocity.Y > num188) projectile.velocity.Y = num188;
                    if (Math.Abs(projectile.velocity.X) + Math.Abs(projectile.velocity.Y) < num188 * 0.4)
                    {
                        if (projectile.velocity.X < 0f)
                            projectile.velocity.X = projectile.velocity.X - num189 * 1.1f;
                        else
                            projectile.velocity.X = projectile.velocity.X + num189 * 1.1f;
                    }
                    else if (projectile.velocity.Y == num188)
                    {
                        if (projectile.velocity.X < num191)
                            projectile.velocity.X = projectile.velocity.X + num189;
                        else if (projectile.velocity.X > num191) projectile.velocity.X = projectile.velocity.X - num189;
                    }
                    else if (projectile.velocity.Y > 4f)
                    {
                        if (projectile.velocity.X < 0f)
                            projectile.velocity.X = projectile.velocity.X + num189 * 0.9f;
                        else
                            projectile.velocity.X = projectile.velocity.X - num189 * 0.9f;
                    }
                }
                else
                {
                    // if (!Flies && projectile.BehindTiles() && projectile.soundDelay == 0)
                    // if (Main.netMode != NetmodeID.MultiplayerClient)
                    // {
                    // projectile.soundDelay = 120;

                    // Main.PlaySound(undergroundSound, projectile.position);
                    // if (Main.netMode == NetmodeID.Server) SendSoundPacket();
                    // }

                    num193 = (float) Math.Sqrt(num191 * num191 + num192 * num192);
                    var num196 = Math.Abs(num191);
                    var num197 = Math.Abs(num192);
                    var num198 = num188 / num193;
                    num191 *= num198;
                    num192 *= num198;
                    if (ShouldRun())
                    {
                        if (Main.netMode != 1 &&
                            projectile.position.Y / 16f > (Main.rockLayer + Main.maxTilesY) / 2.0)
                        {
                            projectile.active = false;
                            var num200 = (int) projectile.ai[0];
                            while (num200 > 0 && num200 < 200 && Main.projectile[num200].active &&
                                   Main.projectile[num200].aiStyle == projectile.aiStyle)
                            {
                                var num201 = (int) Main.projectile[num200].ai[0];
                                Main.projectile[num200].active = false;
                                // projectile.life = 0;
                                if (Main.netMode == 2) NetMessage.SendData(23, -1, -1, null, num200);
                                num200 = num201;
                            }

                            if (Main.netMode == 2) NetMessage.SendData(23, -1, -1, null, projectile.whoAmI);
                        }

                        num191 = 0f;
                        num192 = num188;
                    }

                    var flag21 = false;
                    if (projectile.type == 87)
                    {
                        if ((projectile.velocity.X > 0f && num191 < 0f || projectile.velocity.X < 0f && num191 > 0f ||
                             projectile.velocity.Y > 0f && num192 < 0f || projectile.velocity.Y < 0f && num192 > 0f) &&
                            Math.Abs(projectile.velocity.X) + Math.Abs(projectile.velocity.Y) > num189 / 2f &&
                            num193 < 300f)
                        {
                            flag21 = true;
                            if (Math.Abs(projectile.velocity.X) + Math.Abs(projectile.velocity.Y) < num188)
                                projectile.velocity *= 1.1f;
                        }

                        if (projectile.position.Y > Main.npc[Target].position.Y ||
                            Main.npc[Target].position.Y / 16f > Main.worldSurface ||
                            !Main.npc[Target].active)
                        {
                            flag21 = true;
                            if (Math.Abs(projectile.velocity.X) < num188 / 2f)
                            {
                                if (projectile.velocity.X == 0f)
                                    projectile.velocity.X = projectile.velocity.X - projectile.direction;
                                projectile.velocity.X = projectile.velocity.X * 1.1f;
                            }
                            else
                            {
                                if (projectile.velocity.Y > -num188)
                                    projectile.velocity.Y = projectile.velocity.Y - num189;
                            }
                        }
                    }

                    if (!flag21)
                    {
                        if (projectile.velocity.X > 0f && num191 > 0f || projectile.velocity.X < 0f && num191 < 0f ||
                            projectile.velocity.Y > 0f && num192 > 0f || projectile.velocity.Y < 0f && num192 < 0f)
                        {
                            if (projectile.velocity.X < num191)
                            {
                                projectile.velocity.X = projectile.velocity.X + num189;
                            }
                            else
                            {
                                if (projectile.velocity.X > num191)
                                    projectile.velocity.X = projectile.velocity.X - num189;
                            }

                            if (projectile.velocity.Y < num192)
                            {
                                projectile.velocity.Y = projectile.velocity.Y + num189;
                            }
                            else
                            {
                                if (projectile.velocity.Y > num192)
                                    projectile.velocity.Y = projectile.velocity.Y - num189;
                            }

                            if (Math.Abs(num192) < num188 * 0.2 &&
                                (projectile.velocity.X > 0f && num191 < 0f ||
                                 projectile.velocity.X < 0f && num191 > 0f))
                            {
                                if (projectile.velocity.Y > 0f)
                                    projectile.velocity.Y = projectile.velocity.Y + num189 * 2f;
                                else
                                    projectile.velocity.Y = projectile.velocity.Y - num189 * 2f;
                            }

                            if (Math.Abs(num191) < num188 * 0.2 &&
                                (projectile.velocity.Y > 0f && num192 < 0f ||
                                 projectile.velocity.Y < 0f && num192 > 0f))
                            {
                                if (projectile.velocity.X > 0f)
                                    projectile.velocity.X = projectile.velocity.X + num189 * 2f;
                                else
                                    projectile.velocity.X = projectile.velocity.X - num189 * 2f;
                            }
                        }
                        else
                        {
                            if (num196 > num197)
                            {
                                if (projectile.velocity.X < num191)
                                    projectile.velocity.X = projectile.velocity.X + num189 * 1.1f;
                                else if (projectile.velocity.X > num191)
                                    projectile.velocity.X = projectile.velocity.X - num189 * 1.1f;
                                if (Math.Abs(projectile.velocity.X) + Math.Abs(projectile.velocity.Y) < num188 * 0.5)
                                {
                                    if (projectile.velocity.Y > 0f)
                                        projectile.velocity.Y = projectile.velocity.Y + num189;
                                    else
                                        projectile.velocity.Y = projectile.velocity.Y - num189;
                                }
                            }
                            else
                            {
                                if (projectile.velocity.Y < num192)
                                    projectile.velocity.Y = projectile.velocity.Y + num189 * 1.1f;
                                else if (projectile.velocity.Y > num192)
                                    projectile.velocity.Y = projectile.velocity.Y - num189 * 1.1f;
                                if (Math.Abs(projectile.velocity.X) + Math.Abs(projectile.velocity.Y) < num188 * 0.5)
                                {
                                    if (projectile.velocity.X > 0f)
                                        projectile.velocity.X = projectile.velocity.X + num189;
                                    else
                                        projectile.velocity.X = projectile.velocity.X - num189;
                                }
                            }
                        }
                    }
                }

                projectile.rotation = (float) Math.Atan2(projectile.velocity.Y, projectile.velocity.X) + 1.57f;
                if (Head)
                {
                    if (flag18)
                    {
                        if (projectile.localAI[0] != 1f) projectile.netUpdate = true;
                        projectile.localAI[0] = 1f;
                    }
                    else
                    {
                        if (projectile.localAI[0] != 0f) projectile.netUpdate = true;
                        projectile.localAI[0] = 0f;
                    }

                    if ((projectile.velocity.X > 0f && projectile.oldVelocity.X < 0f ||
                         projectile.velocity.X < 0f && projectile.oldVelocity.X > 0f ||
                         projectile.velocity.Y > 0f && projectile.oldVelocity.Y < 0f ||
                         projectile.velocity.Y < 0f && projectile.oldVelocity.Y > 0f) /* && !projectile.justHit*/)
                    {
                        projectile.netUpdate = true;
                        return;
                    }
                }
            }

            CustomBehavior();
        }

        public virtual void InitWorm()
        {
        }

        protected virtual void TargetClosest()
        {
            if (!Head) return;

            Target = -1;
            Player player13 = Main.player[projectile.owner];

            float num1105 = 700f;
            float num1106 = 1000f;

            NPC ownerMinionAttackTargetNPC5 = projectile.OwnerMinionAttackTargetNPC;
            if (ownerMinionAttackTargetNPC5 != null && ownerMinionAttackTargetNPC5.CanBeChasedBy(this))
            {
                float distance = projectile.Distance(ownerMinionAttackTargetNPC5.Center);
                if (distance < num1105 * 2f)
                {
                    Target = ownerMinionAttackTargetNPC5.whoAmI;
                }
            }

            if (Target < 0)
            {
                for (int num1112 = 0; num1112 < 200; num1112++)
                {
                    NPC nPC15 = Main.npc[num1112];
                    if (!nPC15.CanBeChasedBy(this) || !(player13.Distance(nPC15.Center) < num1106))
                    {
                        continue;
                    }

                    float num1113 = projectile.Distance(nPC15.Center);
                    if (num1113 < num1105)
                    {
                        Target = num1112;
                    }
                }
            }
        }

        public virtual bool ShouldRun()
        {
            return false;
        }

        public virtual void CustomBehavior()
        {
        }

        protected void Draw(string texturePath, SpriteBatch spriteBatch, Color drawColor)
        {
            var frameSize = new Vector2(projectile.width, projectile.height);
            var texture = mod.GetTexture(texturePath);

            spriteBatch.Draw
            (
                texture,
                new Vector2(
                    projectile.position.X - Main.screenPosition.X + frameSize.X / 2,
                    projectile.position.Y - Main.screenPosition.Y + frameSize.Y / 2
                ),
                null,
                drawColor,
                projectile.rotation,
                frameSize * 0.5f,
                projectile.scale,
                SpriteEffects.None,
                0f
            );
        }
    }
}