using System;
using UnityEngine;

namespace MJGameSDK
{
    /// <summary>
    /// Steam 管理器。开发阶段默认 Mock；接入 Steamworks.NET 后切换 useMockSteam=false。
    /// </summary>
    public class MJGameSteamManager
    {
        private readonly MJGameConfig _config;
        private bool _initialized;
        private ulong _mockSteamId = 76561198000000001UL;
        private MJGameSteamCallbacks _callbacks;

        public bool IsInitialized => _initialized;
        public bool IsLoggedOn => _initialized && (_config.useMockSteam || IsSteamLoggedOn());

        public MJGameSteamManager(MJGameConfig config)
        {
            _config = config;
        }

        public void Initialize(MonoBehaviour runner, Action<MJGameResult> onComplete)
        {
            if (_config.useMockSteam)
            {
                _initialized = true;
                MJGameLogger.Info("Steam", "Mock Steam initialized (useMockSteam=true)");
                onComplete?.Invoke(MJGameResult.Success());
                return;
            }

#if STEAMWORKS_NET
            try
            {
                if (!Steamworks.SteamAPI.Init())
                {
                    onComplete?.Invoke(MJGameResult.Fail(2001, "SteamAPI.Init failed. Is Steam running?"));
                    return;
                }

                // Demo 常传入业务 MonoBehaviour，不一定挂了 MJGameSDKRunner；
                // RunCallbacks 必须挂到 MJGameSDKRunner.Update，否则取票回调永远不会触发。
                var sdkRunner = EnsureSdkRunner(runner);
                EnsureCallbacksComponent(sdkRunner);
                sdkRunner.SetSteamCallback(Steamworks.SteamAPI.RunCallbacks);
                Steamworks.SteamAPI.RunCallbacks();
                _callbacks.EnsureSteamCallbacksRegistered();

                _initialized = true;
                MJGameLogger.Info("Steam",
                    $"Steamworks initialized, SteamID={Steamworks.SteamUser.GetSteamID()}, loggedOn={Steamworks.SteamUser.BLoggedOn()}, appId={Steamworks.SteamUtils.GetAppID()}, overlayEnabled={Steamworks.SteamUtils.IsOverlayEnabled()}");
                onComplete?.Invoke(MJGameResult.Success());
            }
            catch (Exception e)
            {
                onComplete?.Invoke(MJGameResult.Fail(2001, $"Steam init error: {e.Message}"));
            }
#else
            MJGameLogger.Warn("Steam", "STEAMWORKS_NET not defined, falling back to mock");
            _initialized = true;
            onComplete?.Invoke(MJGameResult.Success());
#endif
        }

        public ulong GetSteamId()
        {
            if (_config.useMockSteam)
                return _mockSteamId;

#if STEAMWORKS_NET
            if (_initialized)
                return Steamworks.SteamUser.GetSteamID().m_SteamID;
#endif
            return _mockSteamId;
        }

        public string GetPersonaName()
        {
            if (_config.useMockSteam)
                return "MockSteamPlayer";

#if STEAMWORKS_NET
            if (_initialized)
                return Steamworks.SteamFriends.GetPersonaName();
#endif
            return "MockSteamPlayer";
        }

        /// <summary>
        /// 获取 Web API Auth Ticket（十六进制字符串），供服务端 AuthenticateUserTicket 验票。
        /// </summary>
        public void GetAuthSessionTicket(Action<string> onTicket, Action<MJGameResult> onError)
        {
            if (_config.useMockSteam)
            {
                var mockTicket = $"MOCK_TICKET_{GetSteamId()}_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}";
                MJGameLogger.Debug("Steam", $"Mock ticket: {mockTicket}");
                onTicket?.Invoke(mockTicket);
                return;
            }

#if STEAMWORKS_NET
            if (!_initialized)
            {
                onError?.Invoke(MJGameResult.Fail(2000, "Steam not initialized"));
                return;
            }

            if (_callbacks == null)
            {
                onError?.Invoke(MJGameResult.Fail(2003, "Steam callbacks not ready"));
                return;
            }

            if (!Steamworks.SteamUser.BLoggedOn())
            {
                onError?.Invoke(MJGameResult.Fail(2002, "Steam user not logged on"));
                return;
            }

            // 必须用 GetAuthTicketForWebApi；GetAuthSessionTicket 不能用于 AuthenticateUserTicket
            // identity 可选，传空串即可；服务端 AuthenticateUserTicket 不依赖该字段
            Steamworks.SteamAPI.RunCallbacks();
            _callbacks.BeginRequestWebApiTicket(string.Empty, 15f, onTicket, onError);
#else
            var fallback = $"MOCK_TICKET_{GetSteamId()}";
            onTicket?.Invoke(fallback);
#endif
        }

        /// <summary>
        /// Mock 模式：生成本地模拟订单号。
        /// </summary>
        public string CreateMockOrderId(string productId)
        {
            return $"MOCK_ORDER_{productId}_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}";
        }

        /// <summary>
        /// 等待 Steam Overlay 微交易授权（正式模式，服务端 InitTxn 后调用）。
        /// </summary>
        public void WaitForMicroTxnAuthorization(
            ulong orderId,
            Action onAuthorized,
            Action<MJGameResult> onError,
            float timeoutSeconds = 120f)
        {
            if (_config.useMockSteam)
            {
                MJGameLogger.Info("Steam", $"Mock MicroTxn authorized: orderId={orderId}");
                onAuthorized?.Invoke();
                return;
            }

#if STEAMWORKS_NET
            if (!_initialized)
            {
                onError?.Invoke(MJGameResult.Fail(2000, "Steam not initialized"));
                return;
            }

            if (_callbacks == null)
            {
                onError?.Invoke(MJGameResult.Fail(2003, "Steam callbacks not ready"));
                return;
            }

            _callbacks.BeginWaitForAuthorization(orderId, timeoutSeconds, onAuthorized, onError);
#else
            onError?.Invoke(MJGameResult.Fail(2003, "Steamworks.NET not available"));
#endif
        }

        public void CancelMicroTxnWait()
        {
            _callbacks?.CancelWait();
        }

        private bool IsSteamLoggedOn()
        {
#if STEAMWORKS_NET
            return Steamworks.SteamAPI.IsSteamRunning() && Steamworks.SteamUser.BLoggedOn();
#else
            return false;
#endif
        }

        private static MJGameSDKRunner EnsureSdkRunner(MonoBehaviour runner)
        {
            var sdkRunner = runner as MJGameSDKRunner
                ?? runner.GetComponent<MJGameSDKRunner>()
                ?? MJGameSDKRunner.Instance;

            if (sdkRunner != null)
                return sdkRunner;

            var go = new GameObject("MJGameSDKRunner");
            UnityEngine.Object.DontDestroyOnLoad(go);
            return go.AddComponent<MJGameSDKRunner>();
        }

        private void EnsureCallbacksComponent(MonoBehaviour host)
        {
            if (_callbacks != null)
                return;

            _callbacks = host.GetComponent<MJGameSteamCallbacks>();
            if (_callbacks == null)
                _callbacks = host.gameObject.AddComponent<MJGameSteamCallbacks>();
        }

        public void Shutdown()
        {
            _callbacks?.CancelWebApiTicketWait();
            _callbacks?.CancelWait();

#if STEAMWORKS_NET
            if (_initialized && !_config.useMockSteam)
                Steamworks.SteamAPI.Shutdown();
#endif
            _initialized = false;
        }
    }
}
