using UnityEngine;
using UnityEngine.SceneManagement;
using FishNet;
using IStalk.Network;
using IStalk.Data;

namespace IStalk.Core
{
    public class LobbyManager : MonoBehaviour
    {
        public static LobbyManager Instance { get; private set; }

        [SerializeField] private GlobalRules_SO _globalRules;

        public event System.Action<string> OnRoomCreated;
        public event System.Action<string> OnRoomJoined;
        public event System.Action<int> OnPlayerCountChanged;
        public event System.Action<string> OnLobbyError;
        public event System.Action OnGameStarting;

        public string RoomCode => RelayClient.Instance?.CurrentRoomCode;
        public int PlayerCount { get; private set; }

        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
                return;
            }
            Instance = this;
            DontDestroyOnLoad(gameObject);

            _globalRules.Initialize();
        }

        private void OnEnable()
        {
            var relay = RelayClient.Instance;
            if (relay == null) return;
            relay.OnRoomCreated += HandleRoomCreated;
            relay.OnRoomJoined += HandleRoomJoined;
            relay.OnPlayerJoined += HandlePlayerJoined;
            relay.OnPlayerLeft += HandlePlayerLeft;
            relay.OnGameStart += HandleGameStart;
            relay.OnError += HandleError;
        }

        private void OnDisable()
        {
            var relay = RelayClient.Instance;
            if (relay == null) return;
            relay.OnRoomCreated -= HandleRoomCreated;
            relay.OnRoomJoined -= HandleRoomJoined;
            relay.OnPlayerJoined -= HandlePlayerJoined;
            relay.OnPlayerLeft -= HandlePlayerLeft;
            relay.OnGameStart -= HandleGameStart;
            relay.OnError -= HandleError;
        }

        public void ConnectToRelay()
        {
            RelayClient.Instance.Connect();
        }

        public void CreateRoom(string playerName)
        {
            GameStartData.PlayerName = playerName;
            RelayClient.Instance.CreateRoom(playerName);
        }

        public void JoinRoom(string roomCode, string playerName)
        {
            GameStartData.PlayerName = playerName;
            RelayClient.Instance.JoinRoom(roomCode, playerName);
        }

        public void StartGame()
        {
            int seed = Random.Range(int.MinValue, int.MaxValue);
            GameStartData.MapSeed = seed;
            GameStartData.PlayerCount = PlayerCount;
            RelayClient.Instance.StartGame(seed);
        }

        private void HandleRoomCreated(string code)
        {
            PlayerCount = 1;
            OnRoomCreated?.Invoke(code);
            OnPlayerCountChanged?.Invoke(PlayerCount);
        }

        private void HandleRoomJoined(string code)
        {
            OnRoomJoined?.Invoke(code);
        }

        private void HandlePlayerJoined(int peerId)
        {
            PlayerCount++;
            OnPlayerCountChanged?.Invoke(PlayerCount);
        }

        private void HandlePlayerLeft(int peerId)
        {
            PlayerCount--;
            OnPlayerCountChanged?.Invoke(PlayerCount);
        }

        private void HandleGameStart()
        {
            OnGameStarting?.Invoke();
            LoadGameScene();
        }

        private void LoadGameScene()
        {
            SceneManager.LoadScene("GameScene");
            SceneManager.sceneLoaded += OnGameSceneLoaded;
        }

        private void OnGameSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            SceneManager.sceneLoaded -= OnGameSceneLoaded;

            if (GameStartData.IsHost)
            {
                InstanceFinder.ServerManager.StartConnection();
                InstanceFinder.ClientManager.StartConnection();
            }
            else
            {
                InstanceFinder.ClientManager.StartConnection();
            }
        }

        private void HandleError(string error)
        {
            OnLobbyError?.Invoke(error);
        }
    }
}
