using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;

namespace _PROJECT.NewHandPresence
{
    public class SmartHandPresence : MonoBehaviour
    {
        public bool showController;
        public bool showHand;

        public InputDeviceCharacteristics controllerCharacteristics;
        public List<ControllerInformationScriptableObject> controllerInformation;

        private InputDevice _targetDevice;
        private GameObject _spawnedController;
        private XRControllerAnimator _xrControllerAnimator;

        private GameObject _spawnedHandModel;
        private Animator _handAnimator;

        private static readonly int Trigger = Animator.StringToHash("Trigger");
        private static readonly int Grip = Animator.StringToHash("Grip");

        // Update is called once per frame
        void Update()
        {
            if (!_targetDevice.isValid)
            {
                TryInitialize();
                return;
            }

            UpdateModelVisibility(_spawnedController, showController && _spawnedController, UpdateControllerAnimation);
            UpdateModelVisibility(_spawnedHandModel, showHand && _spawnedHandModel, UpdateHandAnimation);
        }

        private void UpdateHandAnimation()
        {
            var triggerValue = GetFeatureValueOrZero(CommonUsages.trigger);
            var gripValue = GetFeatureValueOrZero(CommonUsages.grip);

            _handAnimator.SetFloat(Trigger, triggerValue);
            _handAnimator.SetFloat(Grip, gripValue);
        }

        private float GetFeatureValueOrZero(InputFeatureUsage<float> feature)
        {
            return _targetDevice.TryGetFeatureValue(feature, out float value) ? value : 0;
        }

        private void TryInitialize()
        {
            var devices = new List<InputDevice>();
            InputDevices.GetDevicesWithCharacteristics(controllerCharacteristics, devices);

            Debug.Log("Found devices: " + devices.Count);

            if (devices.Count <= 0) return;

            _targetDevice = devices[0];

            Debug.Log("Found device: " + _targetDevice.name + _targetDevice.characteristics);
            
            ControllerInformationScriptableObject controllerInfo =
                controllerInformation.Find(x => _targetDevice.name.ToLower().Contains(x.controllerName.ToLower()));

            if (controllerInfo == null) controllerInfo = controllerInformation[0];

            var transform1 = transform.parent; // Right/Left hand direct position

            _spawnedController = Instantiate(controllerInfo.controllerPrefab,
                transform1.TransformPoint(Quaternion.Euler(controllerInfo.controllerRotationOffset) * controllerInfo.controllerOffset),
                transform1.rotation * Quaternion.Euler(controllerInfo.controllerRotationOffset), 
                transform1);
            _xrControllerAnimator = _spawnedController.GetComponent<XRControllerAnimator>();

            _spawnedHandModel = Instantiate(controllerInfo.handPrefab, 
                transform1.TransformPoint(Quaternion.Euler(controllerInfo.handRotationOffset) * controllerInfo.handOffset),
                transform1.rotation * Quaternion.Euler(controllerInfo.handRotationOffset), 
                transform1);
            _handAnimator = _spawnedHandModel.GetComponent<Animator>();
        }

        private void UpdateControllerAnimation()
        {
            _xrControllerAnimator.UpdateAnimations(_targetDevice);
        }

        private static void UpdateModelVisibility(GameObject obj, bool show, Action updateAnimation)
        {
            obj.SetActive(show);
            if (show)
            {
                updateAnimation();
            }
        }
    }
}