using UnityEngine;
using UnityEngine.UIElements;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Player;
using VOID.Generic.Player.Input;
using VOID.UserInterface.Game.Util;

namespace VOID.UserInterface.Game
{
    public class ActionBarSlotsUI : MonoBehaviour
    {
        public static ActionBarSlotsUI current {get; private set;}
        
        // ActionBar for this unit
        private UnitObject _unit;
        private UnitObjectActionBar _actionBar;
        
        // Visual Elements - Slots
        private VisualElement _slotListElement;
        private VisualElement[] _slotElements;
        private Button _slotsLockerButton;
        private Button _slotsChangerNextButton;
        private Button _slotsChangerPreviousButton;
        private Label _slotsChangerNumberLabel;
        public SlotUI[] slotsUI { get; private set; }
        
        private int _slotsPage = 1;
        private int _slotsPageCount = 4;
        private int _slotsPerPage;
        
        // References
        private ShortcutsInputManager _shortcutsInputManager;
        private PlayerController _playerController;
        
        private void Awake()
        {
            current = this;

            var uiDocument = gameObject.GetComponent<UIDocument>();
            var templateElement = uiDocument.rootVisualElement;
            
            // Find all important elements
            _slotListElement = templateElement.Q("slots"); 
            _slotsChangerNextButton = templateElement.Q("slots-changer").Q<Button>("next");
            _slotsChangerPreviousButton = templateElement.Q("slots-changer").Q<Button>("previous");
            _slotsChangerNumberLabel = templateElement.Q("slots-changer").Q<Label>("number");
            _slotsLockerButton = templateElement.Q<Button>("slots-locker");
            
            // Get all SlotUI used by ActionBar
            _slotElements = _slotListElement.Query(className: "slot").ToList().ToArray();
            _slotsPerPage = _slotElements.Length;
            slotsUI = new SlotUI[_slotsPerPage];
            
            for (var i = 0; i < _slotsPerPage; i++)
            {
                var slotUI = new SlotUI();
                slotUI.Init(_slotElements[i], SlotType.ActionBarSlot, i);
                slotsUI[i] = slotUI;
            }

            _slotListElement.dataSource = this;
            _slotListElement.pickingMode = PickingMode.Position;
        }

        private void Start()
        {
            _shortcutsInputManager = ShortcutsInputManager.current;
            _playerController = PlayerController.current;
            
            // Bind events to action bar page changers
            _slotsChangerNextButton.clicked += OnSlotPageNextButton;
            _slotsChangerPreviousButton.clicked += OnSlotPagePreviousButton;
            _shortcutsInputManager.actionBarNext.performed += _ => OnSlotPageNextButton();
            _shortcutsInputManager.actionBarPrevious.performed += _ => OnSlotPagePreviousButton();

            _playerController.OnActiveUnitChange += OnActiveUnitChange;
        }

        private void OnActiveUnitChange(UnitObject unitObject)
        {
            // Remove listeners from old unit
            if (_unit)
            {
                _unit.unitEvents.onActionBarSet.RemoveListener(OnSlotSet);
                _unit.unitEvents.onActionBarUnSet.RemoveListener(OnSlotUnSet);
            }

            _slotsPage = 1;
            _unit = unitObject;
            _actionBar = unitObject.unitActionBar;

            _slotsChangerNumberLabel.text = _slotsPage.ToString();
            UpdateAllSlots();
            
            // Rebind listeners to new unit
            _unit.unitEvents.onActionBarSet.AddListener(OnSlotSet);
            _unit.unitEvents.onActionBarUnSet.AddListener(OnSlotUnSet);
        }

        private void OnSlotPageNextButton()
        {
            _slotsPage++;
            if (_slotsPage > _slotsPageCount) _slotsPage = 1;
            _slotsChangerNumberLabel.text = _slotsPage.ToString();
            UpdateAllSlots();
        }

        private void OnSlotPagePreviousButton()
        {
            _slotsPage--;
            if (_slotsPage < 1) _slotsPage = _slotsPageCount;
            _slotsChangerNumberLabel.text = _slotsPage.ToString();
            UpdateAllSlots();
        }

        private void OnSlotSet(ActionBarSetEvent actionBarSetEvent)
        {
            UpdateSlot(actionBarSetEvent.index % _slotsPerPage);
        }
        
        private void OnSlotUnSet(ActionBarUnSetEvent actionBarUnSetEvent)
        {
            UpdateSlot(actionBarUnSetEvent.index % _slotsPerPage);
        }

        private void UpdateAllSlots()
        {
            for (var i = 0; i < _slotsPerPage; i++)
                UpdateSlot(i);
        }

        private void UpdateSlot(int index)
        {
            var sourceIndex = (_slotsPage - 1) * _slotsPerPage + index;
            var usable = _actionBar.slots[sourceIndex].usable;
            var ability = _actionBar.slots[sourceIndex].ability;
            
            if (usable) slotsUI[index].Set(usable);
            else if (ability) slotsUI[index].Set(ability);
            else slotsUI[index].Clear();
            
            slotsUI[index].ChangeIndex(sourceIndex);
        }
    }
}
