using System;
using System.Collections.Generic;
using HarmonyLib;
using Monkey.UI;

namespace Monkey.Patching
{

    public static class PatchManager
    {

        private const string UPDATE_EMOTION_METHOD_NAME = "UpdateEmotion";
        private const string CURSOR_VISIBLE_SETTER_NAME = "set_visible";
        private const string EMOTION_ACTIVATED_FIELD_NAME = "m_activado";
        private const string EMOTION_VALUE_FIELD_NAME = "m_valorReal";
        private const string EMOTION_VALUE_ON_UPDATE_FIELD_NAME = "m_valorRealOnUpdate";
        private const string EMOTION_CHANGED_VALUE_FIELD_NAME = "m_valorACambiar";

        public static bool IsFemaleAngerLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Rage>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Rage>(value);
        }

        public static bool IsFemaleArousalLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Arousal>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Arousal>(value);
        }

        public static bool IsFemaleDisappointmentLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Decepcion>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Decepcion>(value);
        }

        public static bool IsFemaleConsentLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.ConsentToHero>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.ConsentToHero>(value);
        }

        public static bool IsFemalePainLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Dolor>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Dolor>(value);
        }

        public static bool IsFemalePleasureLocked
        {
            get => IsEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Placer>();
            set => SetEmotionLocked<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Placer>(value);
        }

        public static bool IsMaleDisgustLocked
        {
            get => IsEmotionLocked<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.AscoMale>();
            set => SetEmotionLocked<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.AscoMale>(value);
        }

        public static bool IsMalePleasureLocked
        {
            get => IsEmotionLocked<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.PlacerMale>();
            set => SetEmotionLocked<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.PlacerMale>(value);
        }

        public static float LockedFemaleAngerValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Rage>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Rage>(value);
        }

        public static float LockedFemaleArousalValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Arousal>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Arousal>(value);
        }

        public static float LockedFemaleDisappointmentValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Decepcion>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Decepcion>(value);
        }

        public static float LockedFemaleConsentValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.ConsentToHero>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.ConsentToHero>(value);
        }

        public static float LockedFemalePainValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Dolor>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Dolor>(value);
        }

        public static float LockedFemalePleasureValue
        {
            get => GetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Placer>();
            set => SetEmotionLockedValue<Assets._ReusableScripts.CuchiCuchi.AI.Emociones.Placer>(value);
        }

        public static float LockedMaleDisgustValue
        {
            get => GetEmotionLockedValue<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.AscoMale>();
            set => SetEmotionLockedValue<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.AscoMale>(value);
        }

        public static float LockedMalePleasureValue
        {
            get => GetEmotionLockedValue<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.PlacerMale>();
            set => SetEmotionLockedValue<Assets.TValle.BeachGirl.Characters.Male.AI.Runtime.Emociones.PlacerMale>(value);
        }

        private static Dictionary<Type, (bool isLocked, float lockedValue)> _lockedEmotionValues;

        static PatchManager()
        {
            _lockedEmotionValues = new Dictionary<Type, (bool isLocked, float lockedValue)>();
        }

        public static void Initialize()
        {
            Harmony.CreateAndPatchAll(typeof(PatchManager));
        }

        private static bool DoesEmotionExist<T>() where T : Assets._ReusableScripts.CuchiCuchi.AI.Emocion
        {
            return _lockedEmotionValues.ContainsKey(typeof(T));
        }

        private static bool IsEmotionLocked<T>() where T : Assets._ReusableScripts.CuchiCuchi.AI.Emocion
        {
            if (!DoesEmotionExist<T>())
                return false;

            return (_lockedEmotionValues.ContainsKey(typeof(T)) ? _lockedEmotionValues[typeof(T)].isLocked : false);
        }

        private static void SetEmotionLocked<T>(bool isLocked) where T : Assets._ReusableScripts.CuchiCuchi.AI.Emocion
        {
            if (!DoesEmotionExist<T>())
                return;

            _lockedEmotionValues[typeof(T)] = (isLocked, _lockedEmotionValues[typeof(T)].lockedValue);
        }

        private static float GetEmotionLockedValue<T>() where T : Assets._ReusableScripts.CuchiCuchi.AI.Emocion
        {
            if (!DoesEmotionExist<T>())
                return 0f;

            return _lockedEmotionValues[typeof(T)].lockedValue;
        }

        private static void SetEmotionLockedValue<T>(float lockedValue) where T : Assets._ReusableScripts.CuchiCuchi.AI.Emocion
        {
            if (!DoesEmotionExist<T>())
                return;

            _lockedEmotionValues[typeof(T)] = (_lockedEmotionValues[typeof(T)].isLocked, lockedValue);
        }

        [HarmonyPatch(typeof(Assets._ReusableScripts.CuchiCuchi.AI.Emocion), UPDATE_EMOTION_METHOD_NAME), HarmonyPrefix]
        private static void Assets__ReusableScripts_CuchiCuchi_AI_Emocion_UpdateEmotion_Patch(Assets._ReusableScripts.CuchiCuchi.AI.Emocion __instance)
        {
            if (!_lockedEmotionValues.ContainsKey(__instance.GetType()))
            {
                float value = Traverse
                    .Create(__instance)
                    .Field<float>(EMOTION_VALUE_FIELD_NAME)
                    .Value;

                _lockedEmotionValues.Add(__instance.GetType(), (false, value));
            }

            Traverse<bool> isEmotionActivatedField = Traverse
                .Create(__instance)
                .Field<bool>(EMOTION_ACTIVATED_FIELD_NAME);

            isEmotionActivatedField.Value = !_lockedEmotionValues[__instance.GetType()].isLocked;

            if (_lockedEmotionValues[__instance.GetType()].isLocked)
            {
                float lockedValue = _lockedEmotionValues[__instance.GetType()].lockedValue;

                Traverse
                    .Create(__instance)
                    .Field<float>(EMOTION_VALUE_FIELD_NAME)
                    .Value = lockedValue;

                Traverse
                    .Create(__instance)
                    .Field<float>(EMOTION_VALUE_ON_UPDATE_FIELD_NAME)
                    .Value = lockedValue;

                Traverse
                    .Create(__instance)
                    .Field<float>(EMOTION_CHANGED_VALUE_FIELD_NAME)
                    .Value = 0f;

                __instance.SetValueNextUpdate(lockedValue);
            }
                
        }

        [HarmonyPatch(typeof(UnityEngine.Cursor), CURSOR_VISIBLE_SETTER_NAME), HarmonyPrefix]
        private static void UnityEngine_Cursor_set_visible_Patch(ref bool __0)
        {
            __0 = (UIManager.IsAnyWindowVisible() ? true : __0);
        }

    }

}
