using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

namespace AudioWallpaper.Tools {
    public class HttpHelper {
        // 使用静态HttpClient实例（推荐）
        private static readonly HttpClient _sharedClient = new HttpClient(
            new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }
        );

        private readonly HttpClient _httpClient;
        private TimeSpan _timeout = TimeSpan.FromSeconds(100);

        /// <summary>
        /// 使用共享的静态HttpClient实例
        /// </summary>
        public HttpHelper() => _httpClient = _sharedClient;

        /// <summary>
        /// 使用自定义HttpClient实例
        /// </summary>
        public HttpHelper(HttpClient httpClient) => _httpClient = httpClient;

        /// <summary>
        /// 设置全局请求超时（默认100秒）
        /// </summary>
        public TimeSpan Timeout {
            get => _timeout;
            set {
                _timeout = value;
                _httpClient.Timeout = _timeout;
            }
        }

        /// <summary>
        /// 异步发送GET请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="queryParams">查询参数</param>
        /// <param name="headers">请求头</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应字符串</returns>
        public async Task<string> GetAsync(
            string url,
            Dictionary<string, string>? queryParams = null,
            Dictionary<string, string>? headers = null,
            CancellationToken cancellationToken = default) {
            var requestUrl = BuildUrlWithQuery(url, queryParams);
            using var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
            AddHeaders(request, headers);

            using var response = await SendWithTimeoutAsync(request, cancellationToken);
            return await HandleResponse(response);
        }

        /// <summary>
        /// 异步发送POST请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="content">请求内容</param>
        /// <param name="contentType">内容类型（默认为application/json）</param>
        /// <param name="headers">请求头</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应字符串</returns>
        public async Task<string> PostAsync(
            string url,
            object content,
            string contentType = "application/json",
            Dictionary<string, string>? headers = null,
            CancellationToken cancellationToken = default) {
            using var request = new HttpRequestMessage(HttpMethod.Post, url);
            AddHeaders(request, headers);
            request.Content = CreateHttpContent(content, contentType);

            using var response = await SendWithTimeoutAsync(request, cancellationToken);
            return await HandleResponse(response);
        }

        private async Task<HttpResponseMessage> SendWithTimeoutAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken) {
            try {
                // 使用CancellationTokenSource实现超时控制
                using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                cts.CancelAfter(_timeout);

                return await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
            } catch (TaskCanceledException) when (!cancellationToken.IsCancellationRequested) {
                throw new TimeoutException($"请求超时 ({_timeout.TotalSeconds}秒)");
            }
        }

        private static string BuildUrlWithQuery(string url, Dictionary<string, string>? queryParams) {
            if (queryParams == null || queryParams.Count == 0) return url;

            var uriBuilder = new UriBuilder(url);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);

            foreach (var param in queryParams) {
                query[param.Key] = param.Value;
            }

            uriBuilder.Query = query.ToString();
            return uriBuilder.ToString();
        }

        private static void AddHeaders(HttpRequestMessage request, Dictionary<string, string>? headers) {
            if (headers == null) return;

            foreach (var header in headers) {
                if (header.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)) {
                    if (request.Content != null) {
                        request.Content.Headers.ContentType = new MediaTypeHeaderValue(header.Value);
                    }
                } else {
                    request.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }
            }
        }

        private static HttpContent CreateHttpContent(object content, string contentType) {
            return contentType.ToLower() switch {
                "application/json" => new StringContent(
                    JsonSerializer.Serialize(content),
                    Encoding.UTF8,
                    "application/json"),

                "application/x-www-form-urlencoded" => new FormUrlEncodedContent(
                    content as IEnumerable<KeyValuePair<string, string>>
                    ?? ConvertToFormData(content)),

                _ => throw new NotSupportedException($"不支持的Content-Type: {contentType}")
            };
        }

        private static IEnumerable<KeyValuePair<string, string>> ConvertToFormData(object data) {
            var formData = new List<KeyValuePair<string, string>>();
            var properties = data.GetType().GetProperties();

            foreach (var prop in properties) {
                var value = prop.GetValue(data)?.ToString() ?? "";
                formData.Add(new KeyValuePair<string, string>(prop.Name, value));
            }

            return formData;
        }

        private static async Task<string> HandleResponse(HttpResponseMessage response) {
            response.EnsureSuccessStatusCode();

            using var stream = await response.Content.ReadAsStreamAsync();
            using var reader = new StreamReader(stream, Encoding.UTF8);
            return await reader.ReadToEndAsync();
        }
    }
}