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

namespace IGP.Multiplayer.Samples
{
    /// <summary>
    /// Minimal public-facing starter demo for external Unity developers.
    /// Attach this next to <see cref="IGPMultiplayerRuntime"/> to verify the
    /// first-room-join, scene gate, realtime and achievement path.
    /// </summary>
    public sealed class IGPUnityStarterDemo : MonoBehaviour
    {
        [Header("References")]
        [SerializeField] private IGPRuntimeManager? coreRuntime = null;
        [SerializeField] private IGPMultiplayerRuntime? multiplayerRuntime = null;

        [Header("Sample Message")]
        [SerializeField] private string debugMessageType = "starter_demo_ping";
        [SerializeField] private string debugText = "hello from unity starter demo";

        [Header("Achievement Sample")]
        [SerializeField] private string unlockAchievementKey = "first_session";
        [SerializeField] private string progressAchievementKey = "matches_played";
        [SerializeField] private double progressValue = 1d;
        [SerializeField] private string progressSourceKey = "starter_demo_match_complete";

        [Header("Auto Actions")]
        [SerializeField] private bool initializeOnStart = true;
        [SerializeField] private bool setSceneGateOnRealtimeReady = true;
        [SerializeField] private string sceneGateValue = "arena-ready";

        private void Awake()
        {
            coreRuntime ??= FindObjectOfType<IGPRuntimeManager>();
            multiplayerRuntime ??= FindObjectOfType<IGPMultiplayerRuntime>();
        }

        private void OnEnable()
        {
            if (multiplayerRuntime == null)
            {
                Debug.LogWarning("[IGP Starter Demo] IGPMultiplayerRuntime not found. Add it to the scene first.");
                return;
            }

            multiplayerRuntime.ConnectionChanged += HandleConnectionStateChanged;
            multiplayerRuntime.RoomChanged += HandleRoomChanged;
            multiplayerRuntime.MessageReceived += HandleMessageReceived;
            multiplayerRuntime.ErrorOccurred += HandleError;
        }

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

            multiplayerRuntime.ConnectionChanged -= HandleConnectionStateChanged;
            multiplayerRuntime.RoomChanged -= HandleRoomChanged;
            multiplayerRuntime.MessageReceived -= HandleMessageReceived;
            multiplayerRuntime.ErrorOccurred -= HandleError;
        }

        private async void Start()
        {
            if (!initializeOnStart || coreRuntime == null)
            {
                return;
            }

            var initialized = await coreRuntime.InitializeAsync();
            if (!initialized)
            {
                Debug.LogError("[IGP Starter Demo] SDK initialization failed.");
            }
        }

        public async void SendStarterMessage()
        {
            if (multiplayerRuntime == null)
            {
                Debug.LogWarning("[IGP Starter Demo] multiplayerRuntime is missing.");
                return;
            }

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

                Debug.Log($"[IGP Starter Demo] Sent message `{debugMessageType}`.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] SendStarterMessage failed: {ex.Message}");
            }
        }

        public async void SetSceneGate()
        {
            if (multiplayerRuntime == null)
            {
                return;
            }

            try
            {
                await multiplayerRuntime.SetSceneGateAsync(sceneGateValue);
                Debug.Log($"[IGP Starter Demo] Scene gate set to `{sceneGateValue}`.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] SetSceneGate failed: {ex.Message}");
            }
        }

        public async void UnlockStarterAchievement()
        {
            if (coreRuntime == null)
            {
                return;
            }

            try
            {
                var result = await IGPSDK.UnlockAchievementAsync(coreRuntime, unlockAchievementKey);
                Debug.Log($"[IGP Starter Demo] UnlockAchievement success={result.success}, duplicated={result.duplicated}, message={result.message}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] UnlockStarterAchievement failed: {ex.Message}");
            }
        }

        public async void ReportStarterAchievementProgress()
        {
            if (coreRuntime == null)
            {
                return;
            }

            try
            {
                var result = await IGPSDK.ReportAchievementProgressAsync(
                    coreRuntime,
                    progressAchievementKey,
                    progressValue,
                    progressSourceKey);

                Debug.Log($"[IGP Starter Demo] ReportAchievementProgress success={result.success}, duplicated={result.duplicated}, message={result.message}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] ReportStarterAchievementProgress failed: {ex.Message}");
            }
        }

        public async void SetGlobalStarterState()
        {
            if (multiplayerRuntime == null)
            {
                return;
            }

            try
            {
                await multiplayerRuntime.SetGlobalStateAsync("starter:lastMessageAt", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
                Debug.Log("[IGP Starter Demo] Updated global starter state.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] SetGlobalStarterState failed: {ex.Message}");
            }
        }

        public async void CallStarterRpc()
        {
            if (multiplayerRuntime == null)
            {
                return;
            }

            try
            {
                var requestId = await multiplayerRuntime.CallRPCAsync(
                    "starter_echo",
                    new
                    {
                        text = debugText,
                        sentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    });

                Debug.Log($"[IGP Starter Demo] RPC dispatched with requestId={requestId}");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] CallStarterRpc failed: {ex.Message}");
            }
        }

        private void HandleRoomChanged(IGPRoomChangedEvent change)
        {
            if (change.Kind == IGPRoomChangeKind.Joined && change.Room != null)
            {
                Debug.Log($"[IGP Starter Demo] Joined room id={change.Room.id}, code={change.Room.code}, host={change.Room.hostId}");
            }
        }

        private async void HandleConnectionStateChanged(IGPMultiplayerConnectionChangedEvent change)
        {
            Debug.Log($"[IGP Starter Demo] Connection changed: state={change.State}, ready={change.IsReady}");

            if (!change.IsReady ||
                !setSceneGateOnRealtimeReady ||
                multiplayerRuntime == null ||
                !string.Equals(multiplayerRuntime.CurrentRoomData.hostId, multiplayerRuntime.PlayerId, StringComparison.Ordinal))
            {
                return;
            }

            try
            {
                await multiplayerRuntime.SetSceneGateAsync(sceneGateValue);
                Debug.Log($"[IGP Starter Demo] Scene gate set to `{sceneGateValue}` after realtime connected.");
            }
            catch (Exception ex)
            {
                Debug.LogError($"[IGP Starter Demo] Automatic scene gate update failed: {ex.Message}");
            }
        }

        private void HandleMessageReceived(IGPMessageReceivedEvent message)
        {
            var payloadJson = message.Content != null ? Newtonsoft.Json.JsonConvert.SerializeObject(message.Content) : "<null>";
            Debug.Log($"[IGP Starter Demo] Message received type={message.MessageType}, payload={payloadJson}");
        }

        private void HandleError(IGPMultiplayerErrorEvent error)
        {
            Debug.LogError($"[IGP Starter Demo] Runtime error: {error}");
        }
    }
}
