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

namespace IGP.Multiplayer.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 IGPMultiplayerRuntime? runtimeManager = null;

        private void Awake()
        {
            runtimeManager ??= FindObjectOfType<IGPMultiplayerRuntime>();
        }

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

            runtimeManager.ConnectionChanged += OnConnectionStateChanged;
            runtimeManager.MessageReceived += OnMessageReceived;
            runtimeManager.ErrorOccurred += OnError;
            runtimeManager.RoomChanged += OnRoomChanged;

            if (runtimeManager.Network != null)
            {
                runtimeManager.Network.DataReceived += OnP2PDataReceived;
            }

            UpdateUiState();
        }

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

            runtimeManager.ConnectionChanged -= OnConnectionStateChanged;
            runtimeManager.MessageReceived -= OnMessageReceived;
            runtimeManager.ErrorOccurred -= OnError;
            runtimeManager.RoomChanged -= OnRoomChanged;

            if (runtimeManager.Network != null)
            {
                runtimeManager.Network.DataReceived -= 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 SetSceneGate()
        {
            if (runtimeManager == null)
            {
                return;
            }

            try
            {
                await runtimeManager.SetSceneGateAsync("arena-ready");
                LogMessage("Scene gate set to `arena-ready`.");
            }
            catch (Exception ex)
            {
                LogMessage($"SetSceneGate 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(IGPMultiplayerConnectionChangedEvent change)
        {
            LogMessage($"Connection changed: state={change.State}, ready={change.IsReady}");
            UpdateUiState();
        }

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

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

        private void OnRoomChanged(IGPRoomChangedEvent change)
        {
            var room = change.Room ?? change.PreviousRoom;
            LogMessage($"Room changed: kind={change.Kind}, id={room?.id}, flags={change.Changes}");
            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.IsRealtimeReady
                ? $"Realtime ready - room={runtimeManager.CurrentRoomCode}"
                : runtimeManager.IsHostedSessionAttached
                    ? $"Room attached - room={runtimeManager.CurrentRoomCode}"
                    : "Disconnected";
            statusText.color = runtimeManager.IsRealtimeReady
                ? Color.green
                : runtimeManager.IsHostedSessionAttached ? Color.yellow : 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}");
        }
    }
}
