using Intrepid.Utilities;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
{
    [CreateAssetMenu(fileName = "Cadence Profile", menuName = "GON/Services/Cadence/Cadence Profile")]
    public sealed class CadenceProfile : ScriptableObject
    {
        [GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float strained;
        [GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float aligned;
        [GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float resonant;

        [GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float strainedSettlement;
        [GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float alignedSettlement;
        [GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float resonantSettlement;
        [GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float lateSettlement;

        [GroupConfigurations("Core Stability"), SerializeField, Range(0, 50)] private float maxCoreCost;
        [GroupConfigurations("Core Stability"), SerializeField, Range(0, 50)] private float resonantRecovery;

        public float MaxCoreCost => maxCoreCost;

        private void OnValidate()
        {
            Validate();
        }

        [GroupDebug, Button(ButtonSizes.Medium)]
        private void Validate()
        {
            strained = Mathf.Clamp01(strained);
            aligned = Mathf.Clamp01(aligned);
            resonant = Mathf.Clamp01(resonant);

            if (aligned < strained) aligned = strained;
            if (resonant < aligned) resonant = aligned;

            strainedSettlement = Mathf.Clamp01(strainedSettlement);
            alignedSettlement = Mathf.Clamp01(alignedSettlement);
            resonantSettlement = Mathf.Clamp01(resonantSettlement);
            lateSettlement = Mathf.Clamp01(lateSettlement);

            maxCoreCost = Mathf.Max(0f, maxCoreCost);
            resonantRecovery = Mathf.Max(0f, resonantRecovery);
        }

        public CadenceEvaluation Evaluate(float t)
        {
            if (t < strained) return StrainedEvaluation();
            if (t < aligned) return AlignedEvaluation();
            if (t < resonant) return ResonantEvaluation();
            return StrainedEvaluation();
        }
        
        public CadenceEvaluation StrainedEvaluation()
        {
            return new CadenceEvaluation(CadenceBand.Strained, strainedSettlement, 0f);
        }

        public CadenceEvaluation AlignedEvaluation()
        {
            return new CadenceEvaluation(CadenceBand.Aligned, alignedSettlement, 0f);
        }

        public CadenceEvaluation ResonantEvaluation()
        {
            return new CadenceEvaluation(CadenceBand.Resonant, resonantSettlement, resonantRecovery);
        }

        public CadenceEvaluation LateEvaluation()
        {
            return new CadenceEvaluation(CadenceBand.Late, lateSettlement, 0f);
        }
    }
}