using System;
using System.Collections.Generic;
using Intrepid.Gameplay.Flooring.Events;
using Intrepid.SimpleEvents;
using Intrepid.Utilities;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Intrepid.Gameplay.Flooring
{
    public class FloorManager : EventListener
    {
        private const float DisabledUpperThreshold = 1_000_000f;
        private const float DisabledUpperMax = 1_000_001f;

        private const float DisabledLowerThreshold = -1_000_000f;
        private const float DisabledLowerMin = -1_000_001f;

        [GroupDebug, SerializeField, ReadOnly] private FloorDetection floorDetection;

        [GroupConfigurations("Upper Fade"), SerializeField] private float upperMax = 5.5f;
        [GroupConfigurations("Upper Fade"), SerializeField] private float upperThreshold = 5.2f;

        [GroupConfigurations("Lower Tint"), SerializeField] private float lowerThreshold = -1.5f;
        [GroupConfigurations("Lower Tint"), SerializeField] private float lowerMin = -9f;

        [GroupConfigurations("Lower Tint"), SerializeField] private Color lowerTintColor = new(0.35f, 0.35f, 0.35f, 1f);

        private List<FloorVisualGroup> FloorVisualGroups { get; } = new();
        
        protected override void InitializeVariables()
        {
            DetectFloorVisualGroups();
        }

        protected override void OnBootstrap()
        {
            ApplyVisibility();
        }

        protected override void Subscriptions()
        {
            Subscribe<EmitFloorDetectionEvent>(e =>
            {
                floorDetection = e.FloorDetection;
            });
        }

        private void Update()
        {
            ApplyVisibility();
        }
        
        private void ApplyVisibility()
        {
            var request = CreateVisibilityRequest();
            foreach (var floorVisualGroup in FloorVisualGroups)
            {
                if (floorVisualGroup.IsNull()) continue;
                floorVisualGroup.SetVisibility(request);
            }
        }

        [GroupDebug, Button(ButtonSizes.Medium)]
        private void DetectFloorVisualGroups()
        {
            FloorVisualGroups.Clear();
            FloorVisualGroups.AddRange(GetComponentsInChildren<FloorVisualGroup>(true));
        }

        private VisibilityRequest CreateVisibilityRequest()
        {
            if (floorDetection.IsNull())
            {
                return new VisibilityRequest
                {
                    VisibilityOriginY = 0,

                    // These values make the shader never enter upper fade.
                    UpperThreshold = DisabledUpperThreshold,
                    UpperMax = DisabledUpperMax,

                    // These values make the shader never enter lower tint.
                    LowerThreshold = DisabledLowerThreshold,
                    LowerMin = DisabledLowerMin,

                    LowerTintColor = Color.white,
                };
            }

            return new VisibilityRequest
            {
                VisibilityOriginY = floorDetection.CurrentFloorHeight,
                UpperThreshold = upperThreshold,
                UpperMax = upperMax,
                LowerThreshold = lowerThreshold,
                LowerMin = lowerMin,
                LowerTintColor = lowerTintColor,
            };
        }
    }
}