using System;
using Server;
using Server.Mobiles;
using System.Collections.Generic;

using Server.ContextMenus;
using Server.Items;

namespace Server.Engines.TreasuresOfKotlCity
{
    public class KotlBattleSimulator : Item, ISpawner
    {
        public static KotlBattleSimulator Instance { get; set; }

        public static int Levels = 7;
        public static Rectangle2D SpawnBounds = new Rectangle2D(500, 2272, 87, 71);
        public static Type[] SpawnTypes = new Type[] { typeof(SpectralKotlWarrior), typeof(SpectralMyrmidexWarrior) };

        public static TimeSpan BattleDuration = TimeSpan.FromMinutes(60);
        public static TimeSpan NextSpawnDuration { get { return TimeSpan.FromSeconds(Utility.RandomMinMax(2, 25)); } }

        private bool _Active;

        [CommandProperty(AccessLevel.GameMaster)]
        public bool Active
        {
            get { return _Active; }
            set
            {
                bool active = _Active;
                _Active = value;

                if (!active && _Active)
                {
                    StartSpawn();
                }
            }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int SpawnCount { get { return Spawn != null ? Spawn.Count : 0; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Level { get; set; }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Kills { get; set; }

        public List<ISpawnable> Spawn { get; set; }

        public bool UnlinkOnTaming { get { return true; } }
        public Point3D HomeLocation { get { return new Point3D(544, 2303, 0); } }
        public int HomeRange { get { return 30; } }

        public int SpawnPerWave { get { return 10 + (Level * 2); } }
        public int KillsPerWave { get { return 20 + (Level * 2); } }

        public Timer Timer { get; set; }

        public KotlBattleSimulator()
            : base(40147)
        {
            Visible = false;
            Movable = false;

            Instance = this;
        }

        private void StartSpawn()
        {
            Kills = 0;
            Level = 0;

            StartTimer();

            for (int i = 0; i < SpawnPerWave; i++)
            {
                Timer.DelayCall(NextSpawnDuration, DoSpawn);
            }
        }

        public void StartTimer()
        {
            EndTimer();

            Timer = Timer.DelayCall(BattleDuration, EndSimulation);
            Timer.Start();
        }

        public void EndTimer()
        {
            if (Timer != null)
            {
                Timer.Stop();
                Timer = null;
            }
        }

        public virtual void GetSpawnProperties(ISpawnable spawn, ObjectPropertyList list)
        { }

        public virtual void GetSpawnContextEntries(ISpawnable spawn, Mobile user, List<ContextMenuEntry> list)
        { }

        public void Remove(ISpawnable spawn)
        {
            if (Spawn != null && Spawn.Contains(spawn))
            {
                Kills++;
                Spawn.Remove(spawn);

                if (Kills >= KillsPerWave)
                {
                    if (Level >= Levels)
                    {
                        EndSimulation();
                        return;
                    }
                    else
                    {
                        IncreaseLevel();
                    }
                }

                Timer.DelayCall(NextSpawnDuration, DoSpawn);
            }
        }

        private void IncreaseLevel()
        {
            int oldMaxCount = SpawnPerWave;

            Level++;
            Kills = 0;

            int inc = SpawnPerWave - oldMaxCount;

            if (inc > 0)
            {
                for (int i = 0; i < inc; i++)
                {
                    Timer.DelayCall(NextSpawnDuration, DoSpawn);
                }
            }
        }

        public void EndSimulation()
        {
            EndTimer();

            if (WheelsOfTime.Instance != null && (WheelsOfTime.Instance.RockBarrier == null || WheelsOfTime.Instance.RockBarrier.Deleted))
            {
                WheelsOfTime.Instance.RockBarrier = new KotlWallAddon();
            }

            WheelsOfTime.Instance.RockBarrier.MoveToWorld(WheelsOfTime.RockBarrierLocation, Map.TerMur);

            if (WheelsOfTime.Instance != null)
            {
                WheelsOfTime.Instance.TimeWarpEnds = DateTime.UtcNow + TimeSpan.FromSeconds(10);
            }

            PowerCoreDockingStation.Stations.ForEach(station =>
            {
                station.Deactivate();
            });

            Active = false;
            Level = 0;
            Kills = 0;

            // What about spawn?
            ColUtility.Free(Spawn);
        }

        private void DoSpawn()
        {
            if (!_Active)
                return;

            Point3D loc;

            do
            {
                loc = Map.TerMur.GetRandomSpawnPoint(SpawnBounds); 
            }
            while (!Map.TerMur.CanSpawnMobile(loc));

            bool strong = Map.Tiles.GetStaticTiles(loc.X, loc.Y, true).Length > 0;
            BaseCreature bc;

            switch (Utility.Random(2))
            {
                default:
                case 0: bc = new SpectralKotlWarrior(strong); break;
                case 1: bc = new SpectralMyrmidexWarrior(strong); break;
            }

            if (bc != null)
            {
                bc.Spawner = this;

                bc.Home = HomeLocation;
                bc.RangeHome = HomeRange;

				bc.OnBeforeSpawn(loc, Map.TerMur);
                bc.MoveToWorld(loc, Map.TerMur);
				bc.OnAfterSpawn();

                if (Spawn == null)
                    Spawn = new List<ISpawnable>();

                Spawn.Add(bc);
            }
        }

        public KotlBattleSimulator(Serial serial)
            : base(serial)
        {
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write(1); // Version

            writer.Write(_Active);
            writer.Write(Level);
            writer.Write(Kills);

            if (Spawn != null)
            {
                writer.Write(Spawn.Count);
                Spawn.ForEach(sp => writer.Write(sp as Mobile));
            }
            else
            {
                writer.Write(0);
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();

            Instance = this;

            _Active = reader.ReadBool();
            Level = reader.ReadInt();
            Kills = reader.ReadInt();

            int count = reader.ReadInt();
            for (int i = 0; i < count; i++)
            {
                BaseCreature bc = reader.ReadMobile() as BaseCreature;

                if (bc != null)
                {
                    bc.Spawner = this;
                    bc.Home = HomeLocation;
                    bc.RangeHome = HomeRange;

                    if (Spawn == null)
                        Spawn = new List<ISpawnable>();

                    Spawn.Add(bc);
                }
            }

            if (_Active)
            {
                StartTimer();

                if (Spawn == null || Spawn.Count == 0)
                {
                    if (Spawn == null)
                        Spawn = new List<ISpawnable>();

                    if (Level >= Levels)
                    {
                        EndSimulation();
                        return;
                    }
                    else
                    {
                        IncreaseLevel();
                    }
                }
                else
                {
                    int toSpawn = Math.Max(0, SpawnPerWave - (Spawn.Count + Kills));

                    if (toSpawn > 0)
                    {
                        for (int i = 0; i < toSpawn; i++)
                        {
                            Timer.DelayCall(NextSpawnDuration, DoSpawn);
                        }
                    }
                }
            }

            // Teleporter Fix
            if (version == 0)
            {
                Timer.DelayCall(TimeSpan.FromSeconds(20), () =>
                    {
                        if (Map != null)
                        {
                            IPooledEnumerable eable = Map.GetItemsInRange(new Point3D(644, 2308, 0), 0);

                            foreach (Item i in eable)
                            {
                                if (i is Teleporter)
                                {
                                    ((Teleporter)i).PointDest = new Point3D(543, 2479, 2);
                                }
                            }
                        }
                    });
            }
        }
    }
}
