using System;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace MJGameSDK
{
    /// <summary>
    /// 客户端公共上下文：设备信息 + 登录后的 user_id，随每个 API 请求自动上报。
    /// </summary>
    public class MJGameClientContext
    {
        public static MJGameClientContext Instance { get; private set; }

        public string DeviceId { get; private set; }
        public string DeviceModel { get; private set; }
        public string Os { get; private set; }
        public string OsVersion { get; private set; }
        public string AppVersion { get; private set; }
        public string SdkVersion { get; private set; }
        public string Language { get; private set; }
        public uint SteamAppId { get; private set; }
        public int UserId { get; private set; }

        public bool HasUserId => UserId > 0;

        public static void Initialize(uint steamAppId = 0)
        {
            Instance = new MJGameClientContext
            {
                DeviceId = SystemInfo.deviceUniqueIdentifier,
                DeviceModel = SystemInfo.deviceModel,
                Os = Application.platform.ToString(),
                OsVersion = SystemInfo.operatingSystem,
                AppVersion = Application.version,
                SdkVersion = MJGameSDKVersion.Version,
                Language = ResolveLanguageCode(),
                SteamAppId = steamAppId,
                UserId = 0
            };
        }

        public void SetSteamAppId(uint steamAppId)
        {
            SteamAppId = steamAppId;
        }

        /// <summary>
        /// 转为短语言码（≤8），与服务端校验及 Steam InitTxn 的 ISO 639 风格一致。
        /// 勿直接用 Application.systemLanguage.ToString()（如 ChineseSimplified 长达 17）。
        /// </summary>
        public static string ResolveLanguageCode()
        {
            switch (Application.systemLanguage)
            {
                case SystemLanguage.Chinese:
                case SystemLanguage.ChineseSimplified:
                    return "zh-CN";
                case SystemLanguage.ChineseTraditional:
                    return "zh-TW";
                case SystemLanguage.Japanese:
                    return "ja";
                case SystemLanguage.Korean:
                    return "ko";
                case SystemLanguage.English:
                    return "en";
                case SystemLanguage.French:
                    return "fr";
                case SystemLanguage.German:
                    return "de";
                case SystemLanguage.Spanish:
                    return "es";
                case SystemLanguage.Russian:
                    return "ru";
                case SystemLanguage.Portuguese:
                    return "pt";
                case SystemLanguage.Italian:
                    return "it";
                case SystemLanguage.Dutch:
                    return "nl";
                case SystemLanguage.Polish:
                    return "pl";
                case SystemLanguage.Turkish:
                    return "tr";
                case SystemLanguage.Arabic:
                    return "ar";
                case SystemLanguage.Thai:
                    return "th";
                case SystemLanguage.Vietnamese:
                    return "vi";
                case SystemLanguage.Indonesian:
                    return "id";
                default:
                    var name = Application.systemLanguage.ToString();
                    return name.Length <= 8 ? name : "en";
            }
        }

        public static void Reset()
        {
            Instance = null;
        }

        public void SetUserId(int userId)
        {
            UserId = userId;
        }

        public void ClearUserId()
        {
            UserId = 0;
        }

        public void ApplyHeaders(UnityWebRequest request)
        {
            if (request == null)
                return;

            SetHeader(request, "X-Device-Id", DeviceId);
            SetHeader(request, "X-Device-Model", DeviceModel);
            SetHeader(request, "X-OS", Os);
            SetHeader(request, "X-OS-Version", OsVersion);
            SetHeader(request, "X-App-Version", AppVersion);
            SetHeader(request, "X-SDK-Version", SdkVersion);
            SetHeader(request, "X-Language", Language);
            if (SteamAppId > 0)
                SetHeader(request, "X-Steam-App-Id", SteamAppId.ToString());

            if (HasUserId)
                SetHeader(request, "X-Client-User-Id", UserId.ToString());
        }

        public string AppendQueryString(string url)
        {
            var query = BuildQueryString();
            if (string.IsNullOrEmpty(query))
                return url;

            return url.Contains("?") ? $"{url}&{query}" : $"{url}?{query}";
        }

        public string MergeIntoJsonBody(string json)
        {
            var fields = BuildJsonFields(json);
            if (string.IsNullOrEmpty(fields))
                return json ?? "{}";

            if (string.IsNullOrEmpty(json) || json == "{}")
                return "{" + fields + "}";

            var trimmed = json.Trim();
            if (trimmed.EndsWith("}"))
                return trimmed.Substring(0, trimmed.Length - 1) + "," + fields + "}";

            return "{" + fields + "}";
        }

        private string BuildQueryString()
        {
            var sb = new StringBuilder();
            AppendQuery(sb, "device_id", DeviceId);
            AppendQuery(sb, "device_model", DeviceModel);
            AppendQuery(sb, "os", Os);
            AppendQuery(sb, "os_version", OsVersion);
            AppendQuery(sb, "app_version", AppVersion);
            AppendQuery(sb, "sdk_version", SdkVersion);
            AppendQuery(sb, "language", Language);
            if (SteamAppId > 0)
                AppendQuery(sb, "steam_app_id", SteamAppId.ToString());
            if (HasUserId)
                AppendQuery(sb, "user_id", UserId.ToString());
            return sb.ToString().TrimStart('&');
        }

        private string BuildJsonFields(string existingJson = null)
        {
            var sb = new StringBuilder();
            AppendJsonFieldIfAbsent(sb, existingJson, "device_id", DeviceId);
            AppendJsonFieldIfAbsent(sb, existingJson, "device_model", DeviceModel);
            AppendJsonFieldIfAbsent(sb, existingJson, "os", Os);
            AppendJsonFieldIfAbsent(sb, existingJson, "os_version", OsVersion);
            AppendJsonFieldIfAbsent(sb, existingJson, "app_version", AppVersion);
            AppendJsonFieldIfAbsent(sb, existingJson, "sdk_version", SdkVersion);
            AppendJsonFieldIfAbsent(sb, existingJson, "language", Language);
            if (SteamAppId > 0 && !JsonContainsKey(existingJson, "steam_app_id"))
                sb.Append("\"steam_app_id\":").Append(SteamAppId).Append(',');
            if (HasUserId && !JsonContainsKey(existingJson, "user_id"))
                sb.Append("\"user_id\":").Append(UserId).Append(',');
            if (sb.Length > 0)
                sb.Length--;
            return sb.ToString();
        }

        private static void SetHeader(UnityWebRequest request, string name, string value)
        {
            if (!string.IsNullOrEmpty(value))
                request.SetRequestHeader(name, value);
        }

        private static void AppendQuery(StringBuilder sb, string key, string value)
        {
            if (string.IsNullOrEmpty(value))
                return;
            sb.Append('&').Append(key).Append('=').Append(UnityWebRequest.EscapeURL(value));
        }

        private static void AppendJsonFieldIfAbsent(StringBuilder sb, string existingJson, string key, string value)
        {
            if (string.IsNullOrEmpty(value) || JsonContainsKey(existingJson, key))
                return;
            sb.Append('"').Append(key).Append("\":\"").Append(EscapeJson(value)).Append("\",");
        }

        private static bool JsonContainsKey(string json, string key)
        {
            if (string.IsNullOrEmpty(json) || string.IsNullOrEmpty(key))
                return false;
            return json.IndexOf("\"" + key + "\":", StringComparison.Ordinal) >= 0;
        }

        private static string EscapeJson(string value)
        {
            return value
                .Replace("\\", "\\\\")
                .Replace("\"", "\\\"")
                .Replace("\n", "\\n")
                .Replace("\r", "\\r")
                .Replace("\t", "\\t");
        }
    }
}
