#nullable enable
using System;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using IGP.UnitySDK.Models;
using IGP.UnitySDK.Network;

namespace IGP.UnitySDK.Samples
{
    /// <summary>
    /// Consolidated hosted playground sample with a simple UGUI surface.
    /// This replaces the old monolithic Arena example scene with a script-first sample.
    /// </summary>
    public sealed class IGPHostedPlaygroundController : MonoBehaviour
    {
        [Header("UI References")]
        [SerializeField] private InputField? messageInput = null;
        [SerializeField] private Text? statusText = null;
        [SerializeField] private Text? logText = null;
        [SerializeField] private ScrollRect? logScrollRect = null;

        [Header("Runtime References")]
        [SerializeField] private IGPRuntimeManager? runtimeManager = null;
        [SerializeField] private IGPEventManager? eventManager = null;

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

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

            runtimeManager.onConnectionStateChanged.AddListener(OnConnectionStateChanged);
            runtimeManager.onMessageReceived.AddListener(OnMessageReceived);
            runtimeManager.onError.AddListener(OnError);
            runtimeManager.onRoomJoined.AddListener(OnRoomJoined);
            runtimeManager.onRoomLeft.AddListener(OnRoomLeft);

            if (runtimeManager.Network != null)
            {
                runtimeManager.Network.OnDataReceived.AddListener(OnP2PDataReceived);
            }

            UpdateUiState();
        }

        private void OnDisable()
        {
            if (runtimeManager == null)
            {
                return;
            }

            runtimeManager.onConnectionStateChanged.RemoveListener(OnConnectionStateChanged);
            runtimeManager.onMessageReceived.RemoveListener(OnMessageReceived);
            runtimeManager.onError.RemoveListener(OnError);
            runtimeManager.onRoomJoined.RemoveListener(OnRoomJoined);
            runtimeManager.onRoomLeft.RemoveListener(OnRoomLeft);

            if (runtimeManager.Network != null)
            {
                runtimeManager.Network.OnDataReceived.RemoveListener(OnP2PDataReceived);
            }
        }

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

            try
            {
                await runtimeManager.RefreshHostedRoomAsync();
                LogMessage("Refreshed hosted room snapshot.");
            }
            catch (Exception ex)
            {
                LogMessage($"RefreshRoom failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.SetReadyAsync(true);
                LogMessage("Local player marked ready.");
            }
            catch (Exception ex)
            {
                LogMessage($"SetReady failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.StartHostedGameAsync();
                LogMessage("StartHostedGameAsync completed.");
            }
            catch (Exception ex)
            {
                LogMessage($"StartGame failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.FinishHostedGameAsync();
                LogMessage("FinishHostedGameAsync completed.");
            }
            catch (Exception ex)
            {
                LogMessage($"FinishGame failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.LeaveHostedRoomAsync();
                LogMessage("LeaveHostedRoomAsync completed.");
            }
            catch (Exception ex)
            {
                LogMessage($"LeaveRoom failed: {ex.Message}");
            }
        }

        public void SendKcpBroadcast()
        {
            if (runtimeManager?.Network == null)
            {
                LogMessage("IGPNetwork is not available yet.");
                return;
            }

            var payload = new
            {
                text = string.IsNullOrWhiteSpace(messageInput?.text) ? "hello from hosted playground" : messageInput!.text,
                sentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
            };

            var json = Newtonsoft.Json.JsonConvert.SerializeObject(payload);
            var bytes = Encoding.UTF8.GetBytes(json);
            var result = runtimeManager.Network.SendReliableData(runtimeManager.PlayerId, "", bytes, (uint)bytes.Length, 101);
            LogMessage($"SendReliableData result={result}");

            if (messageInput != null)
            {
                messageInput.text = string.Empty;
            }
        }

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

            try
            {
                await runtimeManager.SetGlobalStateAsync("playground:lastMessageAt", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
                LogMessage("Updated global state playground:lastMessageAt.");
            }
            catch (Exception ex)
            {
                LogMessage($"SetGlobalState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.GetStateAsync("global", "playground:lastMessageAt");
                LogMessage("Requested global state playground:lastMessageAt.");
            }
            catch (Exception ex)
            {
                LogMessage($"GetState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.ResetStateAsync("global");
                LogMessage("Requested global state reset.");
            }
            catch (Exception ex)
            {
                LogMessage($"ResetState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.RegisterRPCAsync("playground_echo");
                LogMessage("Registered RPC playground_echo.");
            }
            catch (Exception ex)
            {
                LogMessage($"RegisterRpc failed: {ex.Message}");
            }
        }

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

            try
            {
                var requestId = await runtimeManager.CallRPCAsync("playground_echo", new
                {
                    text = string.IsNullOrWhiteSpace(messageInput?.text) ? "hello" : messageInput!.text,
                    playerId = runtimeManager.PlayerId,
                });

                LogMessage($"CallRPCAsync dispatched requestId={requestId}.");
            }
            catch (Exception ex)
            {
                LogMessage($"CallRpc failed: {ex.Message}");
            }
        }

        private void OnConnectionStateChanged(bool connected)
        {
            LogMessage($"Connection changed: connected={connected}");
            UpdateUiState();
        }

        private void OnMessageReceived(string messageType, object? content)
        {
            var payload = content != null ? Newtonsoft.Json.JsonConvert.SerializeObject(content) : "<null>";
            LogMessage($"Realtime message type={messageType}, payload={payload}");
        }

        private void OnError(string error)
        {
            LogMessage($"Runtime error: {error}");
        }

        private void OnRoomJoined(Room room)
        {
            LogMessage($"Joined room: id={room.id}, code={room.code}, host={room.hostId}");
            UpdateUiState();
        }

        private void OnRoomLeft(Room room)
        {
            LogMessage($"Left room: id={room.id}, code={room.code}");
            UpdateUiState();
        }

        private void OnP2PDataReceived(IGPDataReceived data)
        {
            var text = Encoding.UTF8.GetString(data.data);
            LogMessage($"P2P data from {data.remote_peer}: {text}");
        }

        private void UpdateUiState()
        {
            if (statusText == null || runtimeManager == null)
            {
                return;
            }

            statusText.text = runtimeManager.IsWebSocketConnected
                ? $"Connected - room={runtimeManager.CurrentRoomCode}"
                : "Disconnected";
            statusText.color = runtimeManager.IsWebSocketConnected ? Color.green : Color.red;
        }

        private void LogMessage(string message)
        {
            var entry = $"[{DateTime.Now:HH:mm:ss}] {message}";

            if (logText != null)
            {
                logText.text += entry + "\n";
                Canvas.ForceUpdateCanvases();

                if (logScrollRect != null)
                {
                    logScrollRect.verticalNormalizedPosition = 0f;
                }
            }

            Debug.Log($"[IGP Playground] {message}");
        }
    }
}
