using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;

namespace Monkey.Game
{

    public static class FemaleCharacterAppearanceManager
    {

        private const string FEMALE_CHARACTER_APPEARANCE_GAME_OBJECT_PATH = "AlteradatorsAppearance";

        private const string APPEARANCE_MODIFICATORS_DICTIONARY_FIELD_NAME = "m_mapaDeValoresUsando";

        private static readonly Dictionary<string, List<string>> _appearanceModificators = new Dictionary<string, List<string>>()
        {
            { "FaceYoung", new List<string>() { "Morpher_FACE_Young" } },
            { "FaceOld", new List<string>() { "Morpher_FACE_Old" } },
            { "BodyScale", new List<string>() { "Scala_Puppet_" } },
            { "BodyFat", new List<string>() { "Morpher_BODY_fat_" } },
            { "BreastsSize", new List<string>() { "Scaler_Seno_L", "Scaler_Seno_R" } },
            { "ButtocksSize", new List<string>() { "Scaler_Nalga_L", "Scaler_Nalga_R" } },
            { "VaginaLabiaSize", new List<string>() { "Scaler_VagLabia_" } },
            { "VaginaHoleSize", new List<string>() { "Scaler_VagHole_" } },
            { "VaginaClitorisSize", new List<string>() { "Scaler_BaseClitoris_" } },
            { "AnusSize", new List<string>() { "Scaler_Anus_" } }
        };

        public static float FaceYoung
        {
            get => GetAverageModificatorValue(_appearanceModificators["FaceYoung"], 0);
            set => SetModificatorValue(_appearanceModificators["FaceYoung"], 0, value);
        }

        public static float FaceOld
        {
            get => GetAverageModificatorValue(_appearanceModificators["FaceOld"], 0);
            set => SetModificatorValue(_appearanceModificators["FaceOld"], 0, value);
        }

        public static float BodyScale
        {
            get => GetAverageModificatorValue(_appearanceModificators["BodyScale"], 0);
            set => SetModificatorValue(_appearanceModificators["BodyScale"], 0, value);
        }

        public static float BodyFat
        {
            get => GetAverageModificatorValue(_appearanceModificators["BodyFat"], 0);
            set => SetModificatorValue(_appearanceModificators["BodyFat"], 0, value);
        }

        public static float BreastsSize
        {
            get => GetAverageModificatorValue(_appearanceModificators["BreastsSize"], 0);
            set => SetModificatorValue(_appearanceModificators["BreastsSize"], 0, value);
        }

        public static float ButtocksSize
        {
            get => GetAverageMultipleModificatorsValue(_appearanceModificators["ButtocksSize"], 4);
            set => SetMultipleModificatorsValue(_appearanceModificators["ButtocksSize"], 4, value);
        }

        public static float VaginaLabiaSize
        {
            get => GetAverageMultipleModificatorsValue(_appearanceModificators["VaginaLabiaSize"], 2);
            set => SetMultipleModificatorsValue(_appearanceModificators["VaginaLabiaSize"], 2, value);
        }

        public static float VaginaHoleSize
        {
            get => GetAverageModificatorValue(_appearanceModificators["VaginaHoleSize"], 0);
            set => SetModificatorValue(_appearanceModificators["VaginaHoleSize"], 0, value);
        }

        public static float VaginaClitorisSize
        {
            get => GetAverageModificatorValue(_appearanceModificators["VaginaClitorisSize"], 0);
            set => SetModificatorValue(_appearanceModificators["VaginaClitorisSize"], 0, value);
        }

        public static float AnusSize
        {
            get => GetAverageModificatorValue(_appearanceModificators["AnusSize"], 0);
            set => SetModificatorValue(_appearanceModificators["AnusSize"], 0, value);
        }

        static FemaleCharacterAppearanceManager()
        {

        }

        private static Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.AlteradoresDeAparienciaFemenina GetFemaleAppearance()
        {
            UnityEngine.GameObject femaleCharacterGameObject = FemaleCharacterManager.GetFemaleCharacterGameObject();

            if (femaleCharacterGameObject == null)
                return null;

            return femaleCharacterGameObject
                .transform
                .Find(FEMALE_CHARACTER_APPEARANCE_GAME_OBJECT_PATH)
                .GetComponent<Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.AlteradoresDeAparienciaFemenina>();
        }

        private static Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.Clases.ModificadoresDeAlterador GetModificator(string name)
        {
            if (String.IsNullOrEmpty(name))
                throw new ArgumentNullException(nameof(name));

            Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.AlteradoresDeAparienciaFemenina femaleAppearance = GetFemaleAppearance();

            if (femaleAppearance == null)
                return null;

            return Traverse
                .Create(femaleAppearance)
                .Field<Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.Mapas.Abstracts.MapaDeValoresDeAlteradoresBase>(APPEARANCE_MODIFICATORS_DICTIONARY_FIELD_NAME)
                .Value
                .ObtenerAlteradorModificadores()
                .Where(q => (q.alteradorName == name))
                .FirstOrDefault();
        }

        private static void UpdateModificatorValues()
        {
            Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.AlteradoresDeAparienciaFemenina femaleAppearance = GetFemaleAppearance();

            if (femaleAppearance != null)
                femaleAppearance.UpdateValores();
        }

        private static float GetAverageModificatorValue(List<string> modificatorNames, int modificatorPropertyIndex)
        {
            if ((modificatorNames == null) || (modificatorNames.Count == 0))
                throw new ArgumentNullException(nameof(modificatorNames));

            List<float> modificatorValues = new List<float>();

            foreach (string modificatorName in modificatorNames)
            {
                Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.Clases.ModificadoresDeAlterador modificator = GetModificator(modificatorName);

                if (modificator == null)
                    continue;

                modificatorValues.Add(modificator.modificadores[modificatorPropertyIndex]);
            }

            return modificatorValues.Average();
        }

        private static float GetAverageMultipleModificatorsValue(List<string> modificatorNames, int modificatorProperties)
        {
            if ((modificatorNames == null) || (modificatorNames.Count == 0))
                throw new ArgumentNullException(nameof(modificatorNames));

            List<float> modificatorValues = new List<float>();

            for (int i = 0; i < modificatorProperties; i++)
                modificatorValues.Add(GetAverageModificatorValue(modificatorNames, i));

            return modificatorValues.Average();
        }

        private static void SetModificatorValue(List<string> modificatorNames, int modificatorPropertyIndex, float value)
        {
            if ((modificatorNames == null) || (modificatorNames.Count == 0))
                throw new ArgumentNullException(nameof(modificatorNames));

            foreach (string modificatorName in modificatorNames)
            {
                Assets._ReusableScripts.CuchiCuchi.Chars.Alteradores.Clases.ModificadoresDeAlterador modificator = GetModificator(modificatorName);

                if (modificator == null)
                    continue;

                modificator.modificadores[modificatorPropertyIndex] = value;
            }

            UpdateModificatorValues();
        }

        private static void SetMultipleModificatorsValue(List<string> modificatorNames, int modificatorProperties, float value)
        {
            if ((modificatorNames == null) || (modificatorNames.Count == 0))
                throw new ArgumentNullException(nameof(modificatorNames));

            for (int i = 0; i < modificatorProperties; i++)
                SetModificatorValue(modificatorNames, i, value);
        }

    }

}
