using System;
using System.Threading;
using UnityEngine;

namespace Combo
{
    /// <summary>
    /// HttpDns 的解析结果。
    /// <para>调用方自行决定：</para>
    /// <para> - IPv4/IPv6 网络协议栈的使用优先级</para>
    /// <para> - IP 地址选择策略</para>
    /// <para> - IP 地址 fallback 策略</para>
    /// </summary>
    public class HttpDnsResult
    {
        /// <summary>
        /// 本结果对应的域名
        /// </summary>
        public string Domain { get; set; }

        /// <summary>
        /// 可用的 IPv4 地址。当 IPv4 网络协议栈不可用时为 null
        /// </summary>
        public string[] IPv4 { get; set; }

        /// <summary>
        /// 可用的 IPv6 地址（裸地址，拼 URL 时调用方自行加 []）。当 IPv6 网络协议栈不可用时为 null
        /// </summary>
        public string[] IPv6 { get; set; }
    }

    /// <summary>
    /// 与 Unity 协程模型兼容的异步解析操作。
    /// <para>用法：</para>
    /// <code>
    /// var op = HttpDns.Resolve(domain);
    /// yield return op;
    /// HttpDnsResult result = op.Result;
    /// </code>
    /// </summary>
    // 线程安全：HttpDnsResolveOperation 是 ThreadPool 工作线程（调用 native SDK）与 Unity
    // 主线程（逐帧协程轮询）之间的跨线程交接。采用 volatile + MemoryBarrier 的「volatile
    // 标志发布」模式：
    //
    //   后台线程                          主线程（CustomYieldInstruction 逐帧轮询）
    //   ────────                          ──────────────────────────────────────
    //   _result = result       ①
    //   Thread.MemoryBarrier() ── 栅栏：上方所有写入提交 ──
    //   _isDone = true         ②（volatile 写）
    //                                     读 _isDone（volatile）→ true      ③
    //                                     读 _result            → 可见      ④
    //
    // happens-before：① → ②（内存栅栏禁重排），② → ③（volatile 跨线程可见），③ → ④
    // （同线程程序序）。故 ① happens-before ④——主线程读到 Result 时其内容已完全可见。
    public class HttpDnsResolveOperation : CustomYieldInstruction
    {
        private HttpDnsResult _result;
        private volatile bool _isDone;

        /// <summary>
        /// 解析结果。仅在 <see cref="IsDone"/> 为 true（协程 yield 返回后）读取。
        /// 解析失败或 HTTPDNS 不可用时为 null。
        /// </summary>
        public HttpDnsResult Result => _result;

        /// <summary>
        /// 解析是否已完成
        /// </summary>
        public bool IsDone => _isDone;

        /// <inheritdoc/>
        public override bool keepWaiting => !_isDone;

        internal void SetResult(HttpDnsResult result)
        {
            _result = result;
            Thread.MemoryBarrier();
            _isDone = true;
        }
    }

    /// <summary>
    /// 统一的 HTTPDNS 域名解析 API。这是一个很薄的 C# 层——只负责调用各平台原生 HTTPDNS SDK
    /// （经桥接层）并解析结果。SDK 的初始化、配置与预解析全部由 native 层负责（在 Unity 引擎
    /// 启动之前的进程生命周期入口完成）。
    /// <para>两个入口：</para>
    /// <para> - <see cref="Resolve"/>：异步非阻塞，主线程协程使用</para>
    /// <para> - <see cref="ResolveSync"/>：同步阻塞，仅工作线程使用</para>
    /// <para>平台桥接逻辑见各 <c>HttpDns&lt;Platform&gt;</c> 文件（Android/IOS/OpenHarmony/Windows）。</para>
    /// </summary>
    public static class HttpDns
    {
        /// <summary>
        /// 异步解析域名。非阻塞，可在主线程安全调用。
        /// <para>协程用法：</para>
        /// <code>
        /// var op = HttpDns.Resolve(domain);
        /// yield return op;
        /// HttpDnsResult result = op.Result;  // 不可用时为 null
        /// </code>
        /// </summary>
        /// <param name="domain">待解析的域名</param>
        // 实现把 ResolveSync() 派发到 ThreadPool，再由 CustomYieldInstruction 逐帧轮询，
        // 而非桥接各平台的异步回调（Java listener / OC block / ArkTS Promise）——
        // ThreadPool + CustomYieldInstruction 的模式三端统一。
        public static HttpDnsResolveOperation Resolve(string domain)
        {
            var op = new HttpDnsResolveOperation();

#if UNITY_WEBGL && !UNITY_EDITOR
            // WebGL 单线程、不支持托管线程（ThreadPool 不可用）：无 HTTPDNS 桥，
            // 直接完成（结果 null，调用方退化系统 DNS），避免协程永久挂起。
            op.SetResult(null);
#else
            ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    op.SetResult(ResolveSync(domain));
                }
                catch (Exception e)
                {
                    Debug.LogError($"[HttpDns] Resolve 失败 {domain}: {e.Message}");
                    op.SetResult(null);
                }
            });
#endif

            return op;
        }

        /// <summary>
        /// 同步解析域名。会阻塞调用线程。
        /// <para>仅可在工作线程调用（例如 Mirror 的连接循环、网络库的 dnsProcess 钩子），
        /// 请勿在 Unity 主线程调用。</para>
        /// <para>解析失败或 HTTPDNS 不可用（如 Editor）时返回 null，<b>永不抛异常</b>——
        /// 调用方应把 null 当作「回退系统 DNS」，异常逃逸会绕过该回退通路。</para>
        /// </summary>
        /// <param name="domain">待解析的域名</param>
        public static HttpDnsResult ResolveSync(string domain)
        {
            if (string.IsNullOrEmpty(domain))
                return null;

            try
            {
#if UNITY_ANDROID && !UNITY_EDITOR
                return HttpDnsAndroid.ResolveSync(domain);
#elif UNITY_IOS && !UNITY_EDITOR
                return HttpDnsIOS.ResolveSync(domain);
#elif UNITY_OPENHARMONY && !UNITY_EDITOR
                return HttpDnsOpenHarmony.ResolveSync(domain);
#else
                // Editor / Windows / WebGL：无 HTTPDNS 桥，返回 null，调用方退化系统 DNS
                return null;
#endif
            }
            catch (Exception e)
            {
                Debug.LogWarning($"[HttpDns] ResolveSync 失败 {domain}: {e.Message}");
                return null;
            }
        }

        /// <summary>
        /// HTTPDNS 域名解析能力是否可用（凭据齐全且 native 层已初始化成功）。
        /// 经 <see cref="ComboSDK.IsFeatureAvailable"/>(<see cref="Feature.HTTPDNS"/>) 对外暴露。
        /// </summary>
        internal static bool IsAvailable()
        {
            try
            {
#if UNITY_ANDROID && !UNITY_EDITOR
                return HttpDnsAndroid.IsAvailable();
#elif UNITY_IOS && !UNITY_EDITOR
                return HttpDnsIOS.IsAvailable();
#elif UNITY_OPENHARMONY && !UNITY_EDITOR
                return HttpDnsOpenHarmony.IsAvailable();
#else
                // Editor / Windows / WebGL：无 HTTPDNS 能力
                return false;
#endif
            }
            catch (Exception e)
            {
                Debug.LogWarning($"[HttpDns] IsAvailable 查询失败: {e.Message}");
                return false;
            }
        }
    }
}
