using System;
using System.Collections.Generic;
using Obvious.Soap;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

namespace Conjure.Input
{
    struct PlayerDevice
    {
        public PlayerEnum Player;
        public int DeviceId;
    }
    
    public class InputInstancier : SerializedMonoBehaviour
    {
        [SerializeField, Required] private InputActionAsset sharedInput;
        [SerializeField, Required] private InputVariablePlayersReference inputVariablePlayersReference;
        [SerializeField, Required] private InputServerReference inputManagerGameobjectReference;

        [SerializeField, FoldoutGroup("Debug"), ReadOnly]
        private InputManagerServer _inputManagerServer;

        private void Awake()
        {
            if (inputManagerGameobjectReference.Value is not null)
            {
                _inputManagerServer = inputManagerGameobjectReference.Value.GetComponent<InputManagerServer>();
            }

            if (_inputManagerServer is null)
            {
                throw new NullReferenceException(
                    $"The gameobject referenced by {inputManagerGameobjectReference.name} should have a InputManagerServer Component attached");
            }

        }
        
        public void PrepareInputClients()
        {
            // Get Devices
            foreach (PlayerDevice playerDevice in GetDevices())
            {
                // For each devices, create a player input client
                InputDevice device = GetDeviceFromId(playerDevice.DeviceId);

                if (device is null)
                {
                    continue;
                }
                
                // COPY AND INIT THE INPUT ACTION
                string inputAssetAsJson = sharedInput.ToJson();
                InputActionAsset sharedInputCopy = InputActionAsset.FromJson(inputAssetAsJson);
                sharedInputCopy.devices = new []{ device };
                sharedInputCopy.Enable();
                    
                // CREATE AN OBJECT TO HOLD THE COMPONENT
                GameObject managerClient = new GameObject();
                managerClient.transform.name = $"Input Manager Client Device {playerDevice.DeviceId}";
                managerClient.AddComponent<InputManagerClient>().Constructor(sharedInputCopy, inputVariablePlayersReference, playerDevice.Player);
            }
        }

        private List<PlayerDevice> GetDevices()
        {
            List<PlayerDevice> deviceList = new List<PlayerDevice>();
            
            int devicePlayerOne = _inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player1);
            if (devicePlayerOne != -1)
            {
                deviceList.Add(new PlayerDevice(){Player = PlayerEnum.Player1, DeviceId = devicePlayerOne});
            }
            
            int devicePlayerTwo = _inputManagerServer.GetDeviceIdFromPlayerEnum(PlayerEnum.Player2);
            if (devicePlayerTwo != -1)
            {
                deviceList.Add(new PlayerDevice(){Player = PlayerEnum.Player2, DeviceId = devicePlayerTwo});
            }

            return deviceList;
        }

        private InputDevice GetDeviceFromId(int deviceId)
        {
            foreach (InputDevice inputDevice in InputSystem.devices)
            {
                if (inputDevice.deviceId == deviceId)
                    return inputDevice;
            }

            return null;
        }
    }
}