using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Services.Console;
using RebootKit.Engine.Services.Input;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.InputSystem;

namespace RebootKit.FPPKit {
    public class PlayerController : IController {
        [System.Serializable]
        public class Config {
            public AssetReferenceT<GameObject> FPPSetupAsset;

            public InputActionReference MoveActionReference;
            public InputActionReference LookActionReference;
            public InputActionReference JumpActionReference;
            public InputActionReference DragObjectActionReference;
            public InputActionReference PrimaryActionReference;
            public InputActionReference SecondaryActionReference;
        }
        
        [CVar("fpp_cam_look_sens", 0.25f)]
        private CVar _sensitivityCVar;
        
        [CVar("p_move_speed", 4.0f)]
        private CVar _movementSpeedCVar;

        [Inject]
        private InputService _inputService;

        private Config _config;
        private FPPActor _player;

        public PlayerController(Config config) {
            _config = config;
        }

        public void Dispose() {
        }

        public async UniTask OnStart(CancellationToken cancellationToken) {
            _inputService.LockCursor();
            _inputService.EnableControls();

            _sensitivityCVar = RR.CVarNumber("fpp_cam_look_sens", 0.25f);
            _movementSpeedCVar = RR.CVarNumber("p_move_speed", 4.0f);

            _player = await RR.World().SpawnActor<FPPActor>(_config.FPPSetupAsset, cancellationToken);

            await Awaitable.NextFrameAsync(cancellationToken);
        }

        public void OnStop() {
            _inputService.DisableControls();
            _inputService.UnlockCursor();
            Object.Destroy(_player);

            RR.World().KillActor(_player);
        }

        public void OnTick() {
            _player.FPPCamera.Sensitivity = _sensitivityCVar.FloatValue;
            _player.Locomotion.MaxMovementSpeed = _movementSpeedCVar.FloatValue;

            Vector2 lookInput = _config.LookActionReference.action.ReadValue<Vector2>();
            _player.FPPCamera.Rotate(lookInput.x, lookInput.y);

            Vector2 moveInput = _config.MoveActionReference.action.ReadValue<Vector2>();
            _player.MoveRight(moveInput.x);
            _player.MoveForward(moveInput.y);

            if (_config.JumpActionReference.action.WasPerformedThisFrame()) {
                _player.Locomotion.Jump();
            }

            _player.Dragger.TargetWorldPosition = _player.FPPCamera.Camera.transform.position + _player.FPPCamera.Camera.transform.forward * _player.DragObjectDistanceFromCamera;

            if (_config.DragObjectActionReference.action.WasPressedThisFrame() && !_player.Dragger.IsDragging) {
                GameObject pickedGameObject = _player.FPPCamera.Sensor.Sense();
                if (pickedGameObject != null && pickedGameObject.TryGetComponent(out Rigidbody rigidbody)) {
                    _player.Dragger.Grab(rigidbody);
                }
            }

            if (_config.DragObjectActionReference.action.WasReleasedThisFrame()) {
                _player.Dragger.Drop();
            }
        }
    }
}