using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using ff14bot.Enums;
using ff14bot.Navigation;
using ff14bot.NeoProfiles;
using Kupo.Helpers;
using Kupo.Settings;
using ff14bot;
using ff14bot.Behavior;
using ff14bot.Helpers;
using ff14bot.Managers;
using ff14bot.Objects;
using Kupo.Settings;
using TreeSharp;
using ff14bot.AClasses;
using Action = TreeSharp.Action;

namespace Kupo
{
    public abstract partial class KupoRoutine : CombatRoutine
    {
        //public override virtual string Name { get { return "Kupo [" + GetType().Name + "]"; } }

        private Form _configForm;

        public override bool WantButton
        {
            get { return true; }
        }


        public static KupoSettings WindowSettings = KupoSettings.Instance;

        public override void OnButtonPress()
        {
            if (_configForm == null || _configForm.IsDisposed || _configForm.Disposing)
                _configForm = new SettingsForm();

            _configForm.ShowDialog();
        }

        #region CombatRoutine implementation

        public virtual void OnPulse()
        {
        }

        public static bool WantHealing = false;

        public override sealed void Pulse()
        {
            Extensions.DoubleCastPreventionDict.RemoveAll(t => DateTime.UtcNow > t);
            if (WantHealing)
                HealTargeting.Instance.Pulse();

            OnPulse();
        }


        protected Composite SummonChocobo()
        {
            return new PrioritySelector(
                new Decorator(r => WindowSettings.SummonChocobo && !Chocobo.Summoned && Chocobo.CanSummon,
                    new Action(r =>
                    {
                        if (MovementManager.IsMoving)
                            Navigator.PlayerMover.MoveStop();

                        Chocobo.Summon();
                        return RunStatus.Failure;
                    }))
                );
        }

        public static bool Resting = false;


        protected Composite DefaultRestBehavior(Selection<float> CurrentEnergy)
        {
            return new PrioritySelector(
                new Decorator(r => Resting, new PrioritySelector(
                    new FailLogger(r => "Waiting to recover our health/mana back"),
                    new Decorator(r => MovementManager.IsMoving, new Action(r => Navigator.PlayerMover.MoveStop())),
                    new Decorator(r => Core.Player.CurrentHealthPercent < WindowSettings.RestHealthDone, new ActionAlwaysSucceed()),
                    new Decorator(r => CurrentEnergy(r) < WindowSettings.RestEnergyDone, new ActionAlwaysSucceed()),
                    new Action(r => Resting = false)
                    )),
                new Decorator(
                    r =>
                        CurrentEnergy(r) < WindowSettings.RestEnergy || Core.Player.CurrentHealthPercent < WindowSettings.RestHealth, new Action(r => Resting = true))
                );
        }

        #region Hidden Overrides

        public virtual void OnInitialize()
        {
        }

        public virtual void OnShutdown()
        {
        }

        internal static KupoRoutine Instance;

        public override sealed void Initialize()
        {
            Logging.Write("Starting " + Name);
            Instance = this;

            GameEvents.OnMapChanged += OnGameEventsOnOnMapChanged;

            TreeHooks.Instance.OnHooksCleared += OnInstanceOnOnHooksCleared;


            UpdateContext();

            // NOTE: Hook these events AFTER the context update.
            OnGameContextChanged += OnOnGameContextChanged;


            RoutineManager.Reloaded += OnRoutineManagerOnReloaded;

            if (!RebuildBehaviors(true))
            {
                return;
            }

            Logging.Write(LogLevel.Verbose, Colors.White, "Verified behaviors can be created!");
            Logging.Write("Initialization complete!");
            OnInitialize();
        }

        private void OnInstanceOnOnHooksCleared(object s, EventArgs e)
        {
            Logging.Write(Colors.White, "Hooks cleared, re-creating behaviors");
            RebuildBehaviors(true);
        }

        private void OnGameEventsOnOnMapChanged(object s, EventArgs e)
        {
            UpdateContext();
        }

        private void OnRoutineManagerOnReloaded(object s, EventArgs e)
        {
            Logging.Write(Colors.White, "Routines were reloaded, re-creating behaviors");
            RebuildBehaviors(true);
        }

        private void OnOnGameContextChanged(object orig, GameContextEventArg ne)
        {
            Logging.Write(Colors.White, "Context changed, re-creating behaviors");
            RebuildBehaviors();
        }

        public sealed override void ShutDown()
        {

            //Clear the events
            GameEvents.OnMapChanged -= OnGameEventsOnOnMapChanged;
            TreeHooks.Instance.OnHooksCleared -= OnInstanceOnOnHooksCleared;
            OnGameContextChanged -= OnOnGameContextChanged;
            RoutineManager.Reloaded -= OnRoutineManagerOnReloaded;

            _lastContext = GameContext.None;

            CompositeBuilder._methods.Clear();
            OnShutdown();
        }

        #endregion

        #endregion

        #region Unit Wrappers

        protected BattleCharacter GetTargetMissingDebuff(GameObject near, string debuff, float distance = -1f)
        {
            return
                UnfriendlyUnits.FirstOrDefault(
                    u => u.Location.Distance3D(near.Location) <= distance && !u.HasAura(debuff, true));
        }

        protected int EnemiesNearTarget(float range)
        {
            var target = Core.Player.CurrentTarget;
            if (target == null)
                return 0;
            var tarLoc = target.Location;
            return UnfriendlyUnits.Count(u => u.ObjectId != target.ObjectId && u.Location.Distance3D(tarLoc) <= range);
        }

        //protected IEnumerable<GameObject> UnfriendlyMeleeUnits { get { return UnfriendlyUnits.Where(u => Actionmanager.InSpellInRangeLOS()); } }

        protected IEnumerable<BattleCharacter> UnfriendlyUnits
        {
            get
            {
                return
                    GameObjectManager.GetObjectsOfType<BattleCharacter>().Where(u => !u.IsDead && u.CanAttack);
            }
        }

        #endregion

        #region Spell Casting

        protected Composite EnsureTarget
        {
            get
            {
                return
                    new Decorator(
                        r =>
                            Core.Player.SpellCastInfo != null &&
                            Core.Player.SpellCastInfo.TargetId != GameObjectManager.EmptyGameObject,
                        new PrioritySelector(
                            r => GameObjectManager.GetObjectByObjectId(Core.Player.SpellCastInfo.TargetId),
                            new Decorator(r => (r as Character) != null && (r as Character).IsDead,
                                new PrioritySelector(
                                    new FailLogger(
                                        r =>
                                            string.Format("Stop casting at {0} because it is dead.",
                                                (r as GameObject).Name)),
                                    new Action(r => Actionmanager.StopCasting()))
                                )));
            }
        }



        #endregion

        protected delegate T Selection<out T>(object context);
    }


}