using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;

namespace ArachnaeSwarm
{
    public class CompAbilityEffect_SprayLiquidMulti : CompAbilityEffect
    {
        private enum State
        {
            Ready,
            Shooting
        }

        private State state = State.Ready;
        private int ticksUntilNextShot;
        private int shotsLeft;
        private List<IntVec3> currentAffectedCells;

        private new CompProperties_AbilitySprayLiquidMulti Props => (CompProperties_AbilitySprayLiquidMulti)props;
        private Pawn Pawn => parent.pawn;

        public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
        {
            base.Apply(target, dest);

            if (state == State.Ready)
            {
                currentAffectedCells = AffectedCells(target);
                if (currentAffectedCells.Count > 0)
                {
                    Fire(currentAffectedCells);
                    
                    shotsLeft = Props.shotCount - 1;
                    if (shotsLeft > 0)
                    {
                        state = State.Shooting;
                        ticksUntilNextShot = Props.ticksBetweenShots;
                    }
                }
            }
        }

        public override void CompTick()
        {
            base.CompTick();

            if (state == State.Shooting)
            {
                if (ticksUntilNextShot > 0)
                {
                    ticksUntilNextShot--;
                }
                else
                {
                    if (shotsLeft > 0)
                    {
                        Fire(currentAffectedCells);
                        shotsLeft--;
                        ticksUntilNextShot = Props.ticksBetweenShots;
                    }
                    
                    if (shotsLeft <= 0)
                    {
                        state = State.Ready;
                        currentAffectedCells = null;
                    }
                }
            }
        }
        
        private void Fire(List<IntVec3> cells)
        {
            if (Pawn == null || !Pawn.Spawned || Props.projectileDef == null || cells == null)
            {
                state = State.Ready;
                return;
            }

            if (Props.sprayEffecter != null)
            {
                Effecter eff = Props.sprayEffecter.Spawn(Pawn.Position, Pawn.Map);
                eff.Cleanup();
            }

            foreach (var cell in cells)
            {
                if (Pawn.Position.IsValid && cell.IsValid)
                {
                    Projectile projectile = (Projectile)GenSpawn.Spawn(Props.projectileDef, Pawn.Position, Pawn.Map);
                    projectile.Launch(Pawn, Pawn.DrawPos, cell, cell, ProjectileHitFlags.IntendedTarget);
                }
            }
        }

        public override void DrawEffectPreview(LocalTargetInfo target)
        {
            GenDraw.DrawFieldEdges(AffectedCells(target));
        }

        public override bool AICanTargetNow(LocalTargetInfo target)
        {
            if (Pawn.Faction != null)
            {
                foreach (IntVec3 item in AffectedCells(target))
                {
                    List<Thing> thingList = item.GetThingList(Pawn.Map);
                    for (int i = 0; i < thingList.Count; i++)
                    {
                        if (thingList[i].Faction == Pawn.Faction)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        private List<IntVec3> AffectedCells(LocalTargetInfo target)
        {
            List<Pair<IntVec3, float>> tmpCellDots = new List<Pair<IntVec3, float>>();
            List<IntVec3> tmpCells = new List<IntVec3>();
            
            tmpCellDots.Clear();
            tmpCells.Clear();
            tmpCellDots.Add(new Pair<IntVec3, float>(target.Cell, 999f));

            if (Props.numCellsToHit > 1)
            {
                Vector3 vector = Pawn.Position.ToVector3Shifted().Yto0();
                Vector3 vector2 = target.Cell.ToVector3Shifted().Yto0();
                IntVec3[] array;
                int num;
                if (Props.numCellsToHit < 10)
                {
                    array = GenAdj.AdjacentCells;
                    num = 8;
                }
                else
                {
                    array = GenRadial.RadialPattern;
                    num = Props.numCellsToHit + 5;
                }
                for (int i = 0; i < num; i++)
                {
                    IntVec3 first = target.Cell + array[i];
                    Vector3 vector3 = first.ToVector3Shifted().Yto0();
                    float second = Vector3.Dot((vector3 - vector).normalized, (vector3 - vector2).normalized);
                    tmpCellDots.Add(new Pair<IntVec3, float>(first, second));
                }
                tmpCellDots.SortByDescending(x => x.Second);
            }

            Map map = Pawn.Map;
            int num2 = Mathf.Min(tmpCellDots.Count, Props.numCellsToHit);
            for (int j = 0; j < num2; j++)
            {
                IntVec3 first2 = tmpCellDots[j].First;
                if (!first2.InBounds(map)) continue;

                if (first2.Filled(map))
                {
                    Building_Door door = first2.GetDoor(map);
                    if (door == null || !door.Open) continue;
                }

                if (parent.verb.TryFindShootLineFromTo(Pawn.Position, first2, out var _, ignoreRange: true))
                {
                    tmpCells.Add(first2);
                }
            }
            return tmpCells;
        }
    }
}