using Controller.Bicycle;
using SicknessReduction.Visual.Vignetting;
using UnityEngine;
using UnityEngine.Serialization;

namespace SicknessReduction
{
    //TODO: also based on slopes
    public class DynamicReductionSource : MonoBehaviour
    {
        private const float MAX_SLOPE_ANGLE = 8.531f;

        public RbBicycleController bikeController;

        [Header("Configuration")] public bool useSpeed = true;
        public bool useSteer = true;
        public bool useSlope = true;

        public float speedMultiplier = 1f;
        public float slopeMultiplier = 1f;
        public float steerMultiplier = 1f;

        [Header("Restriction Data")] public float minValue = 0.3f;
        public float maxValue = 0.7f;
        public float maxValueChangePerSecond = 0.8f;

        [FormerlySerializedAs("threshold")] [Tooltip("Depending on Vignetting source -> deg or deg/s")]
        public float steerThreshold = 20f;

        public float speedThreshold = 1f;
        public float slopeThreshold = 1f;

        private ValueBasedRestrictionSuggestor steerAngleSuggestor;
        private ValueBasedRestrictionSuggestor slopeSuggestor;
        private ValueAndTimeBasedRestrictionSuggestor speedSuggestor;

        protected float currentValue;

        public float CurrentValue => currentValue;

        protected virtual void Start()
        {
            if (bikeController == null) Debug.LogError("bike controller = null!");
            if (useSteer)
                steerAngleSuggestor =
                    new ValueBasedRestrictionSuggestor(steerThreshold, minValue, maxValue,
                        bikeController.maxSteeringAngle); //deg
            if (useSpeed)
                speedSuggestor = new ValueAndTimeBasedRestrictionSuggestor(speedThreshold, minValue,
                    maxValue, 25f, 1.111f /*4kmh*/, 3);
            if (useSlope)
                slopeSuggestor =
                    new ValueBasedRestrictionSuggestor(slopeThreshold, minValue, maxValue, MAX_SLOPE_ANGLE);
        }

        protected virtual void Update()
        {
            if (useSteer) steerAngleSuggestor.Value = bikeController.CurrentSteerAngle;
            if (useSpeed) speedSuggestor.UpdateValue(bikeController.CurrentSpeed);
            if (useSlope) slopeSuggestor.Value = bikeController.CurrentGradientDeg;

            var steerSuggestion = useSteer ? steerAngleSuggestor.Suggestion * steerMultiplier : 0f;
            var speedSuggestion = useSpeed ? speedSuggestor.Suggestion * speedMultiplier : 0f;
            var slopeSuggestion = useSlope ? slopeSuggestor.Suggestion * slopeMultiplier : 0f;
            var desiredValue = Mathf.Min(Mathf.Max(steerSuggestion, speedSuggestion, slopeSuggestion), maxValue);

            var desiredChange = desiredValue - currentValue;
            var maxChange = Time.deltaTime * maxValueChangePerSecond;
            var change = Mathf.Sign(desiredChange) * Mathf.Min(Mathf.Abs(desiredChange), maxChange);

            currentValue = Mathf.Clamp(currentValue + change, 0, 1);

            //Debug.Log($"SuggestionValue = {currentValue}");
        }
    }
}