using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using VOID.Generic.Objects.Abstract;
using VOID.UserInterface;
using VOID.UserInterface.Game.Party;
using VOID.UserInterface.Game.Util;

namespace VOID.Generic.Player.Util
{
    public static class SelectUtil
    {
        private const int LayerMask = LayerManager.Static | LayerManager.Dynamic;

        /// <summary>
        /// Returns result from SelectFromUI() or SelectFromScene() depending on whether it was over UI
        /// </summary>
        public static SelectUtilResult Select()
        {
            return GameUI.current.isCursorOverUI ? SelectFromUI() : SelectFromScene();
        }
        
        /// <summary>
        /// Returns clicked AbstractObject or position if something else clicked from scene
        /// </summary>
        public static SelectUtilResult SelectFromScene()
        {
            if (GameUI.current.isCursorOverUI) return new SelectUtilResult();

            var hit = SelectHit();

            if (!hit.collider) return new SelectUtilResult();

            var hitPosition = hit.point;
            var hitObject = hit.collider.gameObject.GetComponentInParent<AbstractObject>();
            
            if (hitObject == PlayerController.current.activeUnit) return new SelectUtilResult();

            if (!hitObject) return new SelectUtilResult(hitPosition);
            
            return new SelectUtilResult(hitPosition, hitObject);
        }

        /// <summary>
        /// Returns clicked AbstractObject or BasicAbility from UI. Using cached position and ui elements if provided.
        /// </summary>
        public static SelectUtilResult SelectFromUI(List<VisualElement> cachedElements = null)
        {
            if (cachedElements is { Count: 0 }) return new SelectUtilResult();
            if (cachedElements is null && !GameUI.current.isCursorOverUI) return new SelectUtilResult();

            // Here we only handle first element - we don't care whats behind it
            switch (GameUI.current.PickTopComponentUI(cachedElements))
            {
                case SlotUI slotUI: return new SelectUtilResult(slotUI).WithUI(cachedElements);
                case UnitPortraitUI unitPortraitUI: return new SelectUtilResult(unitPortraitUI).WithUI(cachedElements);
                default: return new SelectUtilResult();
            }
        }

        /// <summary>
        /// Returns Vector3 of clicked position
        /// </summary>
        public static Vector3 SelectPosition()
        {
            return SelectHit().point;
        }

        /// <summary>
        /// Returns <see cref="RaycastHit"/> of clicked position
        /// </summary>
        public static RaycastHit SelectHit()
        {
            Physics.Raycast(
                Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()),
                out var hit,
                Mathf.Infinity,
                LayerMask);

            return hit;
        }
    }
}