using System;
using System.Collections;
using Intrepid.Diagnostics;
using Intrepid.GameManagers;
using Intrepid.Gameplay.Codex.UI;
using Intrepid.Gameplay.Entities.Player.ActionBelt.Events;
using Intrepid.Utilities;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.ActionBelt.UI
{
    public class CodexActionBeltUI : CodexWindowUI
    {
        [GroupInjections, SerializeField] private ActionBeltManager actionBeltManager;
        [GroupInjections, SerializeField] private CodexActionBeltSlotControllerUI left;
        [GroupInjections, SerializeField] private CodexActionBeltSlotControllerUI right;
        [GroupInjections, SerializeField] private CodexActionBeltControllerUI center;
        [GroupInjections, SerializeField] private CodexActionBeltActivationProgressControllerUI activationProgress;
        
        private Func<ActionEnvelope> GetFocus { get; set; }
        private Func<ActionEnvelope> SneakPeekRight { get; set; }
        private Func<ActionEnvelope> SneakPeekLeft { get; set; }
        private Func<int> GetNumberOfActionsInBelt { get; set; } = () => 0;
        private bool IsOptionActive => GetNumberOfActionsInBelt() > 1;

        protected override void InitializeVariables()
        {
            base.InitializeVariables();
            GetFocus = () => actionBeltManager.Focus;
            SneakPeekRight = () => actionBeltManager.PeekRight;
            SneakPeekLeft = () => actionBeltManager.PeekLeft;
            GetNumberOfActionsInBelt = () => actionBeltManager.Count;
        }

        protected override void Subscriptions()
        {
            base.Subscriptions();
            Subscribe<ActionBeltShowEvent>(_ => ManagedWindow.Show());
            Subscribe<ActionBeltHideEvent>(_ => ManagedWindow.Hide());

            Subscribe<ActionBeltActivationStartedEvent>(WhenActionBeltActivationStarted);
            Subscribe<ActionBeltActivationProgressEvent>(WhenActionBeltActivationProgress);
            Subscribe<ActionBeltActivationCanceledEvent>(WhenActionBeltActivationCanceled);
            
            Subscribe<ActionBeltUIToRightEvent>(WhenActionBeltNextRight);
            Subscribe<ActionBeltUIToLeftEvent>(WhenActionBeltNextLeft);
            
            Subscribe<ActionBeltUITakeActionEvent>(WhenActionBeltUITakeAction);
            Subscribe<ActionBeltUIDropEvent>(WhenActionBeltUIDrop);
        }
        
        private void WhenActionBeltActivationStarted(ActionBeltActivationStartedEvent e)
        {
            DLogger.LogDebug("activation started");
        }

        private void WhenActionBeltActivationProgress(ActionBeltActivationProgressEvent e)
        {
            activationProgress.SetProgress(e.Progress);
        }

        private void WhenActionBeltActivationCanceled(ActionBeltActivationCanceledEvent e)
        {
            StartActivationCancelReturn();
        }

        private void StartActivationCancelReturn()
        {
            activationProgress.CancelAndReturnToZero();
        }
        
        private void WhenActionBeltUIDrop(ActionBeltUIDropEvent e)
        {
            if (!actionBeltManager.IsOperational) return;
            center.Drop();
        }
        
        private IEnumerator UpdateContentNextFrame()
        {
            yield return null;
            var focus = GetFocus();
            activationProgress.UpdateContent(focus);
            center.UpdateContent(focus);
        }

        public override void BeforeOpen()
        {
            base.BeforeOpen();
            StartCoroutine(UpdateContentNextFrame());
        }
        
        private void WhenActionBeltNextRight(ActionBeltUIToRightEvent e)
        {
            if (!actionBeltManager.IsOperational) return;
            if (!IsOptionActive) return;
            SwitchRight();
            center.Reset();
            StartCoroutine(UpdateContentNextFrame());
        }

        private void WhenActionBeltNextLeft(ActionBeltUIToLeftEvent e)
        {
            if (!actionBeltManager.IsOperational) return;
            if (!IsOptionActive) return;
            SwitchLeft();
            center.Reset();
            StartCoroutine(UpdateContentNextFrame());
        }
        
        private void WhenActionBeltUITakeAction(ActionBeltUITakeActionEvent e)
        {
            if (!actionBeltManager.IsOperational) return;
            activationProgress.ResetProgress();
            center.ActionTaken();
            StartCoroutine(UpdateContentNextFrame());
        }
        
        private void Update()
        {
            if (!actionBeltManager.IsOperational)
            {
                activationProgress.ResetProgress();
                Proxy.Instance.EventBus.Raise(new ActionBeltUICloseEvent());
                return;
            }
            
            switch (GetNumberOfActionsInBelt())
            {
                case 0:
                    activationProgress.ResetProgress();
                    Proxy.Instance.EventBus.Raise(new ActionBeltUICloseEvent());
                    return;
                case 1:
                    left.Deactivate();
                    right.Deactivate();
                    break;
                case > 1:
                    left.Activate(SneakPeekLeft().ActionCategory);
                    right.Activate(SneakPeekRight().ActionCategory);
                    break;
            }
        }

        [GroupDebug, Button]
        private void SwitchLeft()
        {
            left.BumpRight();
            right.BumpLeft();
            center.Selected();
        }
        
        [GroupDebug, Button]
        private void SwitchRight()
        {
            left.BumpRight();
            right.BumpLeft();
            center.Selected();
        }
    }
}