using Sirenix.Utilities;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using VOID.Generic.Objects.Usable;
using VOID.Generic.Objects.Weapon;
using VOID.Generic.Objects.Wearable;
using VOID.UserInterface.Game.Util;
using VOID.ScriptableObjects.Abilities;

namespace VOID.UserInterface.Game.Tooltip
{

    public class TooltipManagerUI : MonoBehaviour
    {
        public static TooltipManagerUI current { get; private set; }
        
        // Tooltip elements
        private VisualElement _rootElement;
        private WeaponTooltipUI _weaponTooltip;
        private WearableTooltipUI _wearableTooltip;
        private UsableTooltipUI _usableTooltip;
        private ItemTooltipUI _itemTooltip;
        private AbilityTooltipUI _abilityTooltip;
        private StatusTooltipUI _statusTooltip;
        
        // Size
        private ITooltip _currentTooltip;

        private void Awake()
        {
            current = this;
            
            // Tooltip elements init
            var uiDocument = gameObject.GetComponent<UIDocument>();
            var templateElement = uiDocument.rootVisualElement;
            
            // SAFEGUARD - tooltips should never be clickable, if somehow UI was built weird then this should fix it
            templateElement.Query<VisualElement>().ForEach(element => element.pickingMode = PickingMode.Ignore);
            
            _rootElement = templateElement.Q("root-tooltip");
            _weaponTooltip = new WeaponTooltipUI(_rootElement.Q("weapon-tooltip"));
            _wearableTooltip = new WearableTooltipUI(_rootElement.Q("wearable-tooltip"));
            _usableTooltip = new UsableTooltipUI(_rootElement.Q("usable-tooltip"));
            _itemTooltip = new ItemTooltipUI(_rootElement.Q("item-tooltip"));
            _abilityTooltip = new AbilityTooltipUI(_rootElement.Q("ability-tooltip"));
            _statusTooltip = new StatusTooltipUI(_rootElement.Q("status-tooltip"));
        }

        private void Start()
        {
            // Events - cursor entering and leaving slotUI
            GameUI.current.ElementsUnderCursorChanged += OnElementsUnderCursorChanged;
            
            Hide();
        }

        private void OnElementsUnderCursorChanged()
        {
            switch (GameUI.current.PickTopComponentUI())
            {
                case SlotUI slotUI:
                    Show(slotUI);
                    break;
                case StatusUI statusUI:
                    Show(statusUI);
                    break;
                default:
                    Hide();
                    break;
            }
        }

        private void Update() => MoveTooltip();

        private void MoveTooltip()
        {
            var size = _currentTooltip.GetSize() / GameUI.current.scale;
            var minPos = Vector2.zero;
            var maxPos = new Vector2(Screen.width - size.x, Screen.height - size.y);
            var pos = Mouse.current.position.ReadValue().Clamp(minPos, maxPos);
            
            var panelPos = RuntimePanelUtils.ScreenToPanel(_rootElement.panel, pos);
            _rootElement.style.bottom = new StyleLength(panelPos.y);
            _rootElement.style.left = new StyleLength(panelPos.x);
        }
        
        private void Show(SlotUI slotUI)
        {
            if (slotUI.isEmpty) return;
            
            Hide();
            
            _rootElement.style.display = DisplayStyle.Flex;
            enabled = true;
            
            switch (slotUI.item)
            {
                case WeaponObject weapon:
                    _weaponTooltip.Show(weapon);
                    _currentTooltip = _weaponTooltip;
                    return;
                case WearableObject wearable:
                    _wearableTooltip.Show(wearable);
                    _currentTooltip = _wearableTooltip;
                    return;
                case UsableObject usable:
                    _usableTooltip.Show(usable);
                    _currentTooltip = _usableTooltip;
                    return;
                case { } item:
                    _itemTooltip.Show(item);
                    _currentTooltip = _itemTooltip;
                    return;
            }

            switch (slotUI.ability)
            {
                // TODO: tutaj może będzie inny tooltip dla podstawowego ataku
                case BasicAttackAbility attackAbility:
                    _abilityTooltip.Show(attackAbility);
                    _currentTooltip = _abilityTooltip;
                    return;
                case { } ability:
                    _abilityTooltip.Show(ability);
                    _currentTooltip = _abilityTooltip;
                    return;
            }

            Hide();
            var itemType = slotUI.item ? slotUI.item.GetType().GetNiceName() : "-----";
            var abilityType = slotUI.ability ? slotUI.ability.GetType().GetNiceName() : "-----";
            Debug.LogWarning("No valid tooltip for '" + itemType + "' or '" + abilityType + "'.");
        }

        private void Show(StatusUI statusUI)
        {
            Hide();
            _rootElement.style.display = DisplayStyle.Flex;
            enabled = true;
            _statusTooltip.Show(statusUI.status);
            _currentTooltip = _statusTooltip;
        }

        private void Hide()
        {
            _weaponTooltip.Hide();
            _wearableTooltip.Hide();
            _usableTooltip.Hide();
            _itemTooltip.Hide();
            _abilityTooltip.Hide();
            _statusTooltip.Hide();
            _rootElement.style.display = DisplayStyle.None;
            enabled = false;
        }
    }
}
