using System;
using System.Collections.Generic;
using Obvious.Soap;
using Obvious.Soap.Attributes;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Conjure.Input
{
    public class InputManagerServer: SerializedMonoBehaviour
    {
        private const int None = (int)PlayerEnum.None;
        
        [SerializeField] private Dictionary<PlayerEnum, int> playerIdDictionary = new Dictionary<PlayerEnum, int>();
        [SerializeField, Required] private InputServerReference scriptableReference;
        private int _numberPlayer = 0;

        private void Awake()
        {
            scriptableReference.Value = gameObject;
        }

        public PlayerEnum RegisterDevice(int deviceId)
        {
            PlayerEnum playerSlot;
            playerSlot = GetPlayerFromDeviceId(deviceId);

            if (playerSlot != PlayerEnum.None)
            {
                return playerSlot;
            }
            
            if (!HasFreeSlot())
            {
                return PlayerEnum.None;
            }

            playerSlot = GetFirstFreeSlot();
            playerIdDictionary[playerSlot] = deviceId;
            _numberPlayer++;
            
            return playerSlot;
        }

        public void UnregisterDevice(int deviceId)
        {
            // TODO refactor this when I get time so it's not a if else doing the same thing at different index
            if (playerIdDictionary.ContainsKey(PlayerEnum.Player1) && playerIdDictionary[PlayerEnum.Player1] == deviceId)
            {
                playerIdDictionary.Remove(PlayerEnum.Player1);
                // Promote Player 2 as player 1 if the player 1 leaves while there's 2 players
                if (playerIdDictionary.ContainsKey(PlayerEnum.Player2))
                {
                    playerIdDictionary[PlayerEnum.Player1] = playerIdDictionary[PlayerEnum.Player2];
                    playerIdDictionary.Remove(PlayerEnum.Player2);
                }
                _numberPlayer--;
            }
            else if (playerIdDictionary.ContainsKey(PlayerEnum.Player2) && playerIdDictionary[PlayerEnum.Player2] == deviceId)
            {
                playerIdDictionary.Remove(PlayerEnum.Player2);
                _numberPlayer--;
            }        
        }

        public int GetDeviceIdFromPlayerEnum(PlayerEnum player)
        {
            if (!playerIdDictionary.ContainsKey(player) || player == PlayerEnum.None)
            {
                return None;
            }

            return playerIdDictionary[player];
        }

        public PlayerEnum GetPlayerFromInt(int playerId)
        {
            switch (playerId)
            {
                case 0:
                    return PlayerEnum.Player1;
                case 1:
                    return PlayerEnum.Player2;
                default:
                    return PlayerEnum.None;
            }
        }
        
        public int GetNumberPlayers()
        {
            return _numberPlayer;
        }
        
        public PlayerEnum GetPlayerFromDeviceId(int deviceId)
        {
            if (playerIdDictionary.ContainsKey(PlayerEnum.Player1) && playerIdDictionary[PlayerEnum.Player1] == deviceId)
            {
                return PlayerEnum.Player1;
            }
            
            if (playerIdDictionary.ContainsKey(PlayerEnum.Player2) && playerIdDictionary[PlayerEnum.Player2] == deviceId)
            {
                return PlayerEnum.Player2;
            }

            return PlayerEnum.None;
        }
        
        private bool HasFreeSlot()
        {
            return playerIdDictionary.Count < 2;
        }

        private PlayerEnum GetFirstFreeSlot()
        {
            if (!playerIdDictionary.ContainsKey(PlayerEnum.Player1))
            {
                return PlayerEnum.Player1;
            }
            
            if (!playerIdDictionary.ContainsKey(PlayerEnum.Player2))
            {
                return PlayerEnum.Player2;
            }

            return PlayerEnum.None;
        }
    }
}