using System.IO;
using System.Linq;
using Decimation.Content.Buffs.Debuffs;
using Decimation.Content.Items.Boss.DuneWyrm;
using Decimation.Content.Items.Misc.Souls;
using Decimation.Content.Items.Vanity.DuneWyrm;
using Decimation.Content.NPCs.DuneWyrm.AncientTombCrawler;
using Decimation.Content.Projectiles;
using Decimation.Lib.NPCs;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace Decimation.Content.NPCs.DuneWyrm
{
    [AutoloadBossHead]
    internal class DuneWyrmHead : DuneWyrm
    {
        private int _previousTile = -1;
        private bool _spawnedAncientTombCrawler;

        public override void SetDefaults()
        {
            npc.lifeMax = 11000;
            npc.damage = 65;
            npc.defense = 15;
            npc.width = 116;
            npc.height = 116;
            Main.npcFrameCount[npc.type] = 1;
            npc.npcSlots = 1f;
            npc.aiStyle = -1;
            npc.boss = true;
            bossBag = ModContent.ItemType<DuneWyrmTreasureBag>();

            DuneWyrmBody.bodyPartsCount = 0;
        }

        public override void Init()
        {
            base.Init();
            head = true;
        }

        public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
        {
            if (Main.rand.NextBool(5) || !Main.expertMode && Main.rand.NextBool(2))
                target.AddBuff(ModContent.BuffType<Hyperthermic>(), Main.expertMode ? 600 : 300);
        }

        public override void OnHitPlayer(Player target, int damage, bool crit)
        {
            if (Main.rand.NextBool(5) || !Main.expertMode && Main.rand.NextBool(2))
                target.AddBuff(ModContent.BuffType<Hyperthermic>(), Main.expertMode ? 600 : 300);
        }

        public override void NPCLoot()
        {
            if (!Main.expertMode)
            {
                Item.NewItem(npc.Center, ModContent.ItemType<SoulofTime>(), Main.rand.Next(15, 26));

                if (Main.rand.NextBool(20)) Item.NewItem(npc.Center, ModContent.ItemType<DuneWyrmMask>());
            }
            else
            {
                npc.DropBossBags();
            }
        }

        public override void BossLoot(ref string name, ref int potionType)
        {
            name = "The Great Dune Wyrm";
            DecimationWorld.downedDuneWyrm = true;

            potionType = ItemID.HealingPotion;
            base.BossLoot(ref name, ref potionType);
        }

        public override void SendExtraAI(BinaryWriter writer)
        {
            writer.Write(_previousTile);
            writer.Write(_spawnedAncientTombCrawler);
        }

        public override void ReceiveExtraAI(BinaryReader reader)
        {
            _previousTile = reader.ReadInt32();
            _spawnedAncientTombCrawler = reader.ReadBoolean();
        }

        public override void CustomBehavior()
        {
            if (npc.life < npc.lifeMax / 2f) ComputeSpeed();
            if (Main.expertMode) SummonSandnado();
            if (Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type != 0 && _previousTile == 0)
                ShootAmmonite();

            if (npc.life <= npc.lifeMax * 0.15f &&
                !_spawnedAncientTombCrawler && !NPC.AnyNPCs(ModContent.NPCType<AncientTombCrawlerHead>()))
            {
                if (Main.netMode != 1)
                    NPC.SpawnOnPlayer(npc.target, ModContent.NPCType<AncientTombCrawlerHead>());
                _spawnedAncientTombCrawler = true;
            }

            _previousTile = Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type;
        }

        public override bool ShouldRun()
        {
            bool playersActive = Main.player.Any(p => p.active);
            bool playersDead = Main.player.Any(p => p.dead);

            return !Main.player[npc.target].ZoneDesert || !playersActive || playersDead;
        }

        private void ComputeSpeed()
        {
            const float ratio = 0.4545454f;
            float deltaLife = npc.lifeMax / 2f - npc.life;
            float addedSpeed = deltaLife * ratio / 1000f;
            speed = BaseSpeed + addedSpeed;
        }

        private void SummonSandnado()
        {
            int tile = Main.tile[(int) npc.Center.X / 16, (int) npc.Center.Y / 16].type;

            if (tile == 0 &&
                _previousTile != 0 && Main.netMode != 1)
                Projectile.NewProjectile(npc.Center, new Vector2(0, 0), ProjectileID.SandnadoHostile, 15, 10f);
        }

        private void ShootAmmonite()
        {
            Main.PlaySound(SoundID.Item14, npc.Center);

            // Smoke
            for (int i = 0; i < 50; i++)
            {
                int dustIndex = Dust.NewDust(new Vector2(npc.position.X, npc.position.Y), npc.width,
                    npc.height, 31, 0f, 0f, 100, default, 2f);
                Main.dust[dustIndex].velocity *= 1.4f;
            }

            float x = npc.position.X + npc.width / 2f - 24f;
            float y = npc.position.Y + npc.height / 2f - 24f;

            for (int g = 0; g < 2; g++)
            {
                int goreIndex =
                    Gore.NewGore(
                        new Vector2(x, y), default, Main.rand.Next(61, 64));
                Main.gore[goreIndex].scale = 1.5f;
                Main.gore[goreIndex].velocity.X += 1.5f;
                Main.gore[goreIndex].velocity.Y += 1.5f;
                goreIndex = Gore.NewGore(
                    new Vector2(x, y), default, Main.rand.Next(61, 64));
                Main.gore[goreIndex].scale = 1.5f;
                Main.gore[goreIndex].velocity.X -= 1.5f;
                Main.gore[goreIndex].velocity.Y += 1.5f;
                goreIndex = Gore.NewGore(
                    new Vector2(x, y), default, Main.rand.Next(61, 64));
                Main.gore[goreIndex].scale = 1.5f;
                Main.gore[goreIndex].velocity.X += 1.5f;
                Main.gore[goreIndex].velocity.Y -= 1.5f;
                goreIndex = Gore.NewGore(
                    new Vector2(x, y), default, Main.rand.Next(61, 64));
                Main.gore[goreIndex].scale = 1.5f;
                Main.gore[goreIndex].velocity.X -= 1.5f;
                Main.gore[goreIndex].velocity.Y -= 1.5f;
            }

            // Ammonite
            int ammoniteNbr = Main.rand.Next(5, 9);

            if (Main.netMode != 1)
                for (int i = 0; i < ammoniteNbr; i++)
                    Projectile.NewProjectile(npc.Center,
                        new Vector2(Main.rand.Next(-8, 9), Main.rand.Next(8, 15)),
                        ModContent.ProjectileType<Ammonite>(), 15, 5f);
        }

        public override bool? DrawHealthBar(byte hbPosition, ref float scale, ref Vector2 position)
        {
            scale = 1.9f; //this make the NPC Health Bar bigger
            return null;
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor)
        {
            Draw("Content/NPCs/DuneWyrm/DuneWyrmHead", spriteBatch, drawColor);

            return false;
        }
    }

    internal class DuneWyrmBody : DuneWyrm
    {
        public static int bodyPartsCount;
        private int _bodyIndex;

        public override void SetDefaults()
        {
            npc.width = 66;
            npc.height = 66;
            npc.damage = 45;
            npc.defense = 5;
            npc.lifeMax = 1;
            npc.dontCountMe = true;

            _bodyIndex = bodyPartsCount++;
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor)
        {
            Vector2 frameSize = new Vector2(npc.width, npc.height);
            Texture2D texture = mod.GetTexture("Content/NPCs/DuneWyrm/DuneWyrmBody");
            Rectangle sourceRectangle = npc.frame;

            if (_bodyIndex % 4 == 0)
            {
                texture = mod.GetTexture("Content/NPCs/DuneWyrm/DuneWyrmBody2");
                sourceRectangle.Width = 88;
                sourceRectangle.Height = 66;
                frameSize.X += 11;
                frameSize.Y -= 10;
            }

            Vector2 position = new Vector2(
                npc.position.X - Main.screenPosition.X + frameSize.X / 2f,
                npc.position.Y - Main.screenPosition.Y + frameSize.Y / 2f
            );

            spriteBatch.Draw
            (
                texture,
                position,
                sourceRectangle,
                drawColor,
                npc.rotation,
                frameSize * 0.5f,
                npc.scale,
                SpriteEffects.None,
                0f
            );

            return false;
        }
    }

    internal class DuneWyrmTail : DuneWyrm
    {
        public override void SetDefaults()
        {
            npc.width = 54;
            npc.height = 54;
            npc.damage = 45;
            npc.defense = 14;
            npc.lifeMax = 1;
            npc.dontCountMe = true;
        }

        public override void Init()
        {
            base.Init();
            tail = true;
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color drawColor)
        {
            Draw("Content/NPCs/DuneWyrm/DuneWyrmTail", spriteBatch, drawColor);

            return false;
        }
    }

    public abstract class DuneWyrm : Worm
    {
        protected const float BaseSpeed = 10f;

        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Great Dune Wyrm");
        }

        public override void Init()
        {
            minLength = 16;
            maxLength = 16;
            tailType = ModContent.NPCType<DuneWyrmTail>();
            bodyType = ModContent.NPCType<DuneWyrmBody>();
            headType = ModContent.NPCType<DuneWyrmHead>();
            speed = BaseSpeed;
            turnSpeed = 0.045f;
            npc.value = Item.buyPrice(gold: 16);
            npc.scale = 1.5f;
            npc.lavaImmune = true;
            npc.noGravity = true;
            npc.noTileCollide = true;
            npc.behindTiles = true;
            npc.knockBackResist = 0f;
            npc.netAlways = true;
            npc.DeathSound = SoundID.NPCDeath18;
            npc.HitSound = SoundID.NPCHit1;
            undergroundSound = mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Custom/Earthquake");
            music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/DuneWyrm");
        }

        protected override void SendSoundPacket()
        {
            GetPacket(DuneWyrmMessageType.UndergroundSound).Send();
        }

        private ModPacket GetPacket(DuneWyrmMessageType type)
        {
            ModPacket packet = mod.GetPacket();
            packet.Write((byte) DecimationModMessageType.DuneWyrm);
            packet.Write(npc.whoAmI);
            packet.Write((byte) type);
            return packet;
        }

        public void HandlePacket(BinaryReader reader)
        {
            DuneWyrmMessageType type = (DuneWyrmMessageType) reader.ReadByte();
            switch (type)
            {
                case DuneWyrmMessageType.UndergroundSound:
                    Main.PlaySound(undergroundSound, npc.Center);
                    break;
            }
        }
    }

    public enum DuneWyrmMessageType
    {
        UndergroundSound
    }
}