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

namespace IGP.UnitySDK.Samples
{
    /// <summary>
    /// Sample focused on realtime messaging and state sync.
    /// </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";

        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);
            }
        }

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

            if (eventManager != null)
            {
                eventManager.onStateChanged.RemoveListener(HandleStateChanged);
            }
        }

        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}");
            }
        }

        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 HandleError(string error)
        {
            Debug.LogError($"[IGP RealtimeSample] Runtime error: {error}");
        }
    }
}
