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

namespace IGP.UnitySDK.Samples
{
    /// <summary>
    /// Sample focused on realtime messaging, state sync, and RPC usage.
    /// </summary>
    public sealed class IGPRealtimeMessagingSample : MonoBehaviour
    {
        [Header("References")]
        [SerializeField] private IGPRuntimeManager? runtimeManager = null;
        [SerializeField] private IGPEventManager? eventManager = null;

        [Header("Message")]
        [SerializeField] private string messageType = "sample_message";
        [SerializeField] private string messageText = "hello realtime";

        [Header("State")]
        [SerializeField] private string globalStateKey = "sample:global";
        [SerializeField] private string playerStateKey = "sample:player";

        [Header("RPC")]
        [SerializeField] private string rpcName = "sample_echo";
        [SerializeField] private string rpcMode = "all";

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

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

            runtimeManager.onMessageReceived.AddListener(HandleRawMessage);
            runtimeManager.onError.AddListener(HandleError);

            if (eventManager != null)
            {
                eventManager.onStateChanged.AddListener(HandleStateChanged);
                eventManager.onRPCCall.AddListener(HandleRpcCall);
                eventManager.onRPCResponse.AddListener(HandleRpcResponse);
            }
        }

        private void OnDisable()
        {
            if (runtimeManager != null)
            {
                runtimeManager.onMessageReceived.RemoveListener(HandleRawMessage);
                runtimeManager.onError.RemoveListener(HandleError);
            }

            if (eventManager != null)
            {
                eventManager.onStateChanged.RemoveListener(HandleStateChanged);
                eventManager.onRPCCall.RemoveListener(HandleRpcCall);
                eventManager.onRPCResponse.RemoveListener(HandleRpcResponse);
            }
        }

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

            try
            {
                await runtimeManager.SendMessageAsync(new Message
                {
                    type = messageType,
                    roomId = runtimeManager.CurrentRoomId,
                    playerId = runtimeManager.PlayerId,
                    reliable = true,
                    content = new
                    {
                        text = messageText,
                        sentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    }
                });

                Debug.Log($"[IGP RealtimeSample] Sent message type={messageType}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] SendMessage failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.SetGlobalStateAsync(globalStateKey, new
                {
                    value = messageText,
                    updatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                });
                Debug.Log($"[IGP RealtimeSample] Set global state key={globalStateKey}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] SetGlobalState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.SetPlayerStateAsync(playerStateKey, new
                {
                    value = messageText,
                    updatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                });
                Debug.Log($"[IGP RealtimeSample] Set player state key={playerStateKey}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] SetPlayerState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.GetStateAsync("global", globalStateKey);
                Debug.Log($"[IGP RealtimeSample] Requested global state key={globalStateKey}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] GetGlobalState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.ResetStateAsync("global");
                Debug.Log("[IGP RealtimeSample] Requested global state reset.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] ResetGlobalState failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.RegisterRPCAsync(rpcName);
                Debug.Log($"[IGP RealtimeSample] Registered RPC `{rpcName}`");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] RegisterRpc failed: {ex.Message}");
            }
        }

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

            try
            {
                await runtimeManager.UnregisterRPCAsync(rpcName);
                Debug.Log($"[IGP RealtimeSample] Unregistered RPC `{rpcName}`");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] UnregisterRpc failed: {ex.Message}");
            }
        }

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

            try
            {
                var requestId = await runtimeManager.CallRPCAsync(
                    rpcName,
                    new
                    {
                        text = messageText,
                        sentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    },
                    rpcMode);

                Debug.Log($"[IGP RealtimeSample] Called RPC `{rpcName}`, requestId={requestId}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP RealtimeSample] CallRpc failed: {ex.Message}");
            }
        }

        private void HandleRawMessage(string incomingMessageType, object? content)
        {
            var payload = content != null ? Newtonsoft.Json.JsonConvert.SerializeObject(content) : "<null>";
            Debug.Log($"[IGP RealtimeSample] Raw message type={incomingMessageType}, payload={payload}");
        }

        private void HandleStateChanged(IGPStateChangeData data)
        {
            var payload = data.value != null ? Newtonsoft.Json.JsonConvert.SerializeObject(data.value) : "<null>";
            Debug.Log($"[IGP RealtimeSample] State changed scope={data.scope}, key={data.key}, value={payload}");
        }

        private void HandleRpcCall(IGPRPCData data)
        {
            var payload = data.data != null ? Newtonsoft.Json.JsonConvert.SerializeObject(data.data) : "<null>";
            Debug.Log($"[IGP RealtimeSample] RPC call name={data.name}, requestId={data.requestId}, payload={payload}");
        }

        private void HandleRpcResponse(IGPRPCData data)
        {
            var payload = data.response != null ? Newtonsoft.Json.JsonConvert.SerializeObject(data.response) : "<null>";
            Debug.Log($"[IGP RealtimeSample] RPC response name={data.name}, requestId={data.requestId}, payload={payload}");
        }

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