using System.Collections;
using HarmonyLib;
using UnityEngine;

namespace MuzikaGromche
{
    static class ScreenFiltersManager
    {
        private const float VibilityThreshold = 0.01f;

        private static bool drunknessChangedThisFrame = false;
        private static float drunkness = 0f;
        public static float Drunkness
        {
            get => drunkness;
            set
            {
                drunkness = value;
                drunknessChangedThisFrame = true;
                ScheduleUpdate();
            }
        }

        private static bool helmetCondensationDropsChangedThisFrame = false;
        private static float helmetCondensationDrops = 0f;
        public static float HelmetCondensationDrops
        {
            get => helmetCondensationDrops;
            set
            {
                helmetCondensationDrops = value;
                helmetCondensationDropsChangedThisFrame = true;
                ScheduleUpdate();
            }
        }

        private static Coroutine? scheduledUpdate = null;

        private static void ScheduleUpdate()
        {
            CancelScheduledUpdate();
            scheduledUpdate = HUDManager.Instance.StartCoroutine(ScheduledUpdate());
        }

        private static void CancelScheduledUpdate()
        {
            if (scheduledUpdate != null)
            {
                HUDManager.Instance.StopCoroutine(scheduledUpdate);
                scheduledUpdate = null;
            }
        }

        private static IEnumerator ScheduledUpdate()
        {
            try
            {
                yield return new WaitForEndOfFrame();
                Update();
            }
            finally
            {
                scheduledUpdate = null;
            }
        }

        private static void Update()
        {
            CancelScheduledUpdate();
            var hud = HUDManager.Instance;

            if (!drunknessChangedThisFrame)
            {
                // animated roll-off
                drunkness = Mathf.Clamp(drunkness - Time.deltaTime / 2f, 0f, 1f);
            }
            drunknessChangedThisFrame = false;
            if (drunkness > VibilityThreshold)
            {
                var moddedDrunknessFilterWeight = StartOfRound.Instance.drunknessSideEffect.Evaluate(drunkness);
                var moddedGasImageAlphaAlpha = moddedDrunknessFilterWeight * 1.5f;
                // set the final value to the greatest of the two, so that we don't accidentally undo TZP's visual effect.
                hud.drunknessFilter.weight = Mathf.Max(hud.drunknessFilter.weight, moddedDrunknessFilterWeight);
                hud.gasImageAlpha.alpha = Mathf.Max(hud.gasImageAlpha.alpha, moddedGasImageAlphaAlpha);
                // Image alpha only makes sense if the animator is running
                hud.gasHelmetAnimator.SetBool("gasEmitting", value: true);
            }
            else
            {
                ClearDrunkness();
            }

            if (!helmetCondensationDropsChangedThisFrame)
            {
                // animated roll-off
                helmetCondensationDrops = Mathf.Clamp(helmetCondensationDrops - Time.deltaTime / 6f, 0f, 1f);
            }
            helmetCondensationDropsChangedThisFrame = false;
            if (helmetCondensationDrops > VibilityThreshold)
            {
                // HelmetCondensationDrops
                Color color = hud.helmetCondensationMaterial.color;
                // set the final value to the greatest of the two, so that we don't accidentally undo steam's visual effect.
                color.a = Mathf.Clamp(Mathf.Max(color.a, helmetCondensationDrops), 0f, 0.27f);
                hud.helmetCondensationMaterial.color = color;
            }
            else
            {
                ClearCondensation();
            }
        }

        public static void Clear()
        {
            ClearDrunkness();
            ClearCondensation();
        }

        private static void ClearDrunkness()
        {
            drunkness = 0f;
            // Only the stop animation if vanilla doesn't animate TZP right now.
            if (GameNetworkManager.Instance.localPlayerController.drunkness == 0f)
            {
                HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", value: false);
            }
            // Vanilla will set drunknessFilter.weight and gasImageAlpha.alpha on the next Update anyway.
        }

        private static void ClearCondensation()
        {
            helmetCondensationDrops = 0f;
        }

        [HarmonyPatch(typeof(HUDManager))]
        internal static class HUDManagerScreenFiltersPatch
        {
            [HarmonyPatch(nameof(HUDManager.SetScreenFilters))]
            [HarmonyPostfix]
            static void SetScreenFiltersPostfix(HUDManager __instance)
            {
                Update();
            }
        }
    }
}
