#nullable enable
using System;
using UnityEngine;
using IGP.UnitySDK.Models;

namespace IGP.UnitySDK.Samples
{
    /// <summary>
    /// Hosted room lifecycle sample for developers who need to understand the end-to-end room flow.
    /// Attach this to the same GameObject as <see cref="IGPRuntimeManager"/>.
    /// For richer lifecycle logs, also add <see cref="IGPEventManager"/> to the scene.
    /// </summary>
    public sealed class IGPRoomLifecycleSample : MonoBehaviour
    {
        [Header("References")]
        [SerializeField] private IGPRuntimeManager? runtimeManager = null;
        [SerializeField] private IGPEventManager? eventManager = null;

        [Header("Room Actions")]
        [SerializeField] private string targetTeamId = "team-a";
        [SerializeField] private bool autoRefreshOnJoin = true;

        private void Awake()
        {
            runtimeManager ??= FindObjectOfType<IGPRuntimeManager>();
            eventManager ??= FindObjectOfType<IGPEventManager>();
        }

        private void OnEnable()
        {
            if (runtimeManager == null)
            {
                Debug.LogWarning("[IGP RoomLifecycle] IGPRuntimeManager not found.");
                return;
            }

            runtimeManager.onConnectionStateChanged.AddListener(HandleConnectionChanged);
            runtimeManager.onRoomJoined.AddListener(HandleRoomJoined);
            runtimeManager.onRoomUpdated.AddListener(HandleRoomUpdated);
            runtimeManager.onRoomLeft.AddListener(HandleRoomLeft);
            runtimeManager.onMapChanged.AddListener(HandleMapChanged);
            runtimeManager.onHostTransferred.AddListener(HandleHostTransferred);
            runtimeManager.onTeamChanged.AddListener(HandleTeamMessage);
            runtimeManager.onTeamInitialized.AddListener(HandleTeamMessage);
            runtimeManager.onTeamStatusUpdated.AddListener(HandleTeamMessage);
            runtimeManager.onError.AddListener(HandleRuntimeError);

            if (eventManager != null)
            {
                eventManager.onPlayerJoined.AddListener(HandlePlayerJoined);
                eventManager.onPlayerLeft.AddListener(HandlePlayerLeft);
                eventManager.onGameStarted.AddListener(HandleGameStarted);
                eventManager.onGameEnded.AddListener(HandleGameEnded);
            }
        }

        private void OnDisable()
        {
            if (runtimeManager != null)
            {
                runtimeManager.onConnectionStateChanged.RemoveListener(HandleConnectionChanged);
                runtimeManager.onRoomJoined.RemoveListener(HandleRoomJoined);
                runtimeManager.onRoomUpdated.RemoveListener(HandleRoomUpdated);
                runtimeManager.onRoomLeft.RemoveListener(HandleRoomLeft);
                runtimeManager.onMapChanged.RemoveListener(HandleMapChanged);
                runtimeManager.onHostTransferred.RemoveListener(HandleHostTransferred);
                runtimeManager.onTeamChanged.RemoveListener(HandleTeamMessage);
                runtimeManager.onTeamInitialized.RemoveListener(HandleTeamMessage);
                runtimeManager.onTeamStatusUpdated.RemoveListener(HandleTeamMessage);
                runtimeManager.onError.RemoveListener(HandleRuntimeError);
            }

            if (eventManager != null)
            {
                eventManager.onPlayerJoined.RemoveListener(HandlePlayerJoined);
                eventManager.onPlayerLeft.RemoveListener(HandlePlayerLeft);
                eventManager.onGameStarted.RemoveListener(HandleGameStarted);
                eventManager.onGameEnded.RemoveListener(HandleGameEnded);
            }
        }

        public async void RefreshRoom()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.RefreshHostedRoomAsync();
                Debug.Log("[IGP RoomLifecycle] RefreshHostedRoomAsync completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] RefreshRoom failed: {ex.Message}");
            }
        }

        public async void SetReady(bool isReady = true)
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.SetReadyAsync(isReady);
                Debug.Log($"[IGP RoomLifecycle] SetReadyAsync({isReady}) completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] SetReady failed: {ex.Message}");
            }
        }

        public async void StartGame()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.StartHostedGameAsync();
                Debug.Log("[IGP RoomLifecycle] StartHostedGameAsync completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] StartGame failed: {ex.Message}");
            }
        }

        public async void FinishGame()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.FinishHostedGameAsync();
                Debug.Log("[IGP RoomLifecycle] FinishHostedGameAsync completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] FinishGame failed: {ex.Message}");
            }
        }

        public async void RequestRematch()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.RequestRematchAsync();
                Debug.Log("[IGP RoomLifecycle] RequestRematchAsync completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] RequestRematch failed: {ex.Message}");
            }
        }

        public async void LeaveRoom()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.LeaveHostedRoomAsync();
                Debug.Log("[IGP RoomLifecycle] LeaveHostedRoomAsync completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] LeaveRoom failed: {ex.Message}");
            }
        }

        public async void ChangeTeam()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.ChangeHostedTeamAsync(targetTeamId);
                Debug.Log($"[IGP RoomLifecycle] ChangeHostedTeamAsync({targetTeamId}) completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] ChangeTeam failed: {ex.Message}");
            }
        }

        private async void HandleRoomJoined(Room room)
        {
            Debug.Log($"[IGP RoomLifecycle] Room joined: id={room.id}, code={room.code}, status={room.status}, host={room.hostId}, players={room.players.Count}");

            if (!autoRefreshOnJoin || runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.RefreshHostedRoomAsync();
                Debug.Log("[IGP RoomLifecycle] Auto refresh after join completed.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RoomLifecycle] Auto refresh failed: {ex.Message}");
            }
        }

        private void HandleRoomUpdated(Room room)
        {
            Debug.Log($"[IGP RoomLifecycle] Room updated: status={room.status}, host={room.hostId}, players={room.players.Count}");
        }

        private void HandleRoomLeft(Room room)
        {
            Debug.Log($"[IGP RoomLifecycle] Room left: id={room.id}, code={room.code}, finalStatus={room.status}");
        }

        private void HandleMapChanged(IGPMapChangeData mapChange)
        {
            var previousMap = $"{mapChange.previousMapPublicId}:{mapChange.previousMapVersionId}";
            var currentMap = $"{mapChange.currentMapPublicId}:{mapChange.currentMapVersionId}";
            Debug.Log($"[IGP RoomLifecycle] Map changed: {previousMap} -> {currentMap}");
        }

        private void HandleHostTransferred(string previousHostId, string currentHostId)
        {
            Debug.Log($"[IGP RoomLifecycle] Host transferred: {previousHostId} -> {currentHostId}");
        }

        private void HandlePlayerJoined(IGPPlayerData player)
        {
            Debug.Log($"[IGP RoomLifecycle] Player joined: id={player.id}, name={player.name}, isHost={player.isHost}");
        }

        private void HandlePlayerLeft(IGPPlayerData player)
        {
            Debug.Log($"[IGP RoomLifecycle] Player left: id={player.id}, name={player.name}");
        }

        private void HandleGameStarted()
        {
            Debug.Log("[IGP RoomLifecycle] Game started event received.");
        }

        private void HandleGameEnded()
        {
            Debug.Log("[IGP RoomLifecycle] Game ended event received.");
        }

        private void HandleConnectionChanged(bool connected)
        {
            Debug.Log($"[IGP RoomLifecycle] Connection changed: connected={connected}");
        }

        private void HandleRuntimeError(string error)
        {
            Debug.LogError($"[IGP RoomLifecycle] Runtime error: {error}");
        }

        private void HandleTeamMessage(string messageType, object? content)
        {
            var payload = content != null ? Newtonsoft.Json.JsonConvert.SerializeObject(content) : "<null>";
            Debug.Log($"[IGP RoomLifecycle] Team event type={messageType}, payload={payload}");
        }
    }
}
