using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MairuiSdk.Exceptions;
using Polly;
using Polly.Retry;

namespace MairuiSdk.Http
{
    public class HttpClientTransport : IDisposable
    {
        public const string DefaultBaseUrl = "https://api.mairuiapi.com";
        public const string DefaultUserAgent = "mairui-csharp/1.0 (+https://www.mairuiapi.com)";

        private static readonly HashSet<int> RetryStatuses = new HashSet<int> { 429, 502, 503, 504 };

        private readonly string _baseUrl;
        private readonly HttpClient _client;
        private readonly AsyncRetryPolicy<HttpResponseMessage> _retryPolicy;

        public HttpClientTransport(
            string baseUrl = null,
            int connectSec = 5,
            int readSec = 60,
            int maxRetries = 3,
            IDictionary<string, string> headers = null)
        {
            _baseUrl = (baseUrl ?? DefaultBaseUrl).TrimEnd('/');
            // .NET Framework 4.6.2 在部分旧系统上默认不含 TLS 1.2，访问 api.mairuiapi.com 会失败
#if NETFRAMEWORK
            try
            {
                System.Net.ServicePointManager.SecurityProtocol |=
                    (System.Net.SecurityProtocolType)3072 | // Tls12
                    (System.Net.SecurityProtocolType)12288; // Tls13（若系统支持则启用）
            }
            catch
            {
                // 忽略：极老系统无对应枚举值时至少保留默认协议
            }
#endif
            _client = new HttpClient
            {
                Timeout = TimeSpan.FromSeconds(connectSec + readSec)
            };
            _client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", DefaultUserAgent);
            _client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json, text/plain, */*");
            _client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate");
            _client.DefaultRequestHeaders.TryAddWithoutValidation("Connection", "keep-alive");
            if (headers != null)
            {
                foreach (var kv in headers)
                    _client.DefaultRequestHeaders.TryAddWithoutValidation(kv.Key, kv.Value);
            }

            _retryPolicy = Policy
                .HandleResult<HttpResponseMessage>(r => RetryStatuses.Contains((int)r.StatusCode))
                .WaitAndRetryAsync(maxRetries <= 0 ? 3 : maxRetries, attempt =>
                    TimeSpan.FromMilliseconds(400 * Math.Pow(2, attempt)));
        }

        public void Dispose() => _client.Dispose();

        public static string QuotePath(string segment)
        {
            return Uri.EscapeDataString(segment.Trim())
                .Replace("%2E", ".")
                .Replace("%2D", "-")
                .Replace("%5F", "_");
        }

        public static Dictionary<string, string> BuildQuery(string st, string et, int? lt, IDictionary<string, string> extra)
        {
            var q = new Dictionary<string, string>();
            if (!string.IsNullOrWhiteSpace(st)) q["st"] = st.Trim();
            if (!string.IsNullOrWhiteSpace(et)) q["et"] = et.Trim();
            if (lt.HasValue) q["lt"] = lt.Value.ToString();
            if (extra != null)
            {
                foreach (var kv in extra)
                    if (kv.Value != null) q[kv.Key] = kv.Value;
            }
            return q;
        }

        public async Task<object> GetJsonAsync(string path, IDictionary<string, string> queryParams, CancellationToken ct = default)
        {
            if (!path.StartsWith("/")) path = "/" + path;
            var url = _baseUrl + path;
            if (queryParams != null && queryParams.Count > 0)
            {
                var qs = string.Join("&", queryParams.Select(kv =>
                    $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"));
                url += "?" + qs;
            }

            HttpResponseMessage resp;
            try
            {
                resp = await _retryPolicy.ExecuteAsync(async () =>
                    await _client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false));
            }
            catch (TaskCanceledException)
            {
                throw new MairuiTimeoutException($"请求超时: {url}");
            }
            catch (HttpRequestException ex)
            {
                throw new MairuiHttpException($"网络错误: {ex.Message}");
            }

            var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
            var payload = SafeJson(body);
            var status = (int)resp.StatusCode;

            if (status == 401 || status == 403)
                throw new MairuiAuthException($"鉴权失败 HTTP {status}: 请检查 licence 是否有效 / 是否欠费限流");
            if (status == 404)
                throw new MairuiHttpException($"资源不存在 HTTP 404: {url}", 404, payload);
            if (status >= 400)
                throw new MairuiHttpException($"HTTP {status}: {url}", status, payload);

            return payload;
        }

        private static object SafeJson(string body)
        {
            if (string.IsNullOrEmpty(body)) return body;
            try
            {
                using (var doc = JsonDocument.Parse(body))
                {
                    return JsonSerializer.Deserialize<object>(body);
                }
            }
            catch
            {
                return body.Length > 500 ? body.Substring(0, 500) : body;
            }
        }
    }
}
