#nullable enable
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IGP.UnitySDK
{
    internal sealed class IGPDirectHttpResponse
    {
        internal int StatusCode { get; }
        internal string Body { get; }

        internal IGPDirectHttpResponse(int statusCode, string body)
        {
            StatusCode = statusCode;
            Body = body ?? string.Empty;
        }
    }

    internal interface IIGPDirectHttpTransport : IDisposable
    {
        Task<IGPDirectHttpResponse> SendAsync(
            HttpMethod method,
            Uri uri,
            string bearerToken,
            string? body,
            CancellationToken cancellationToken);
    }

    internal sealed class IGPSystemDirectHttpTransport : IIGPDirectHttpTransport
    {
        private readonly HttpClient client = new HttpClient { Timeout = Timeout.InfiniteTimeSpan };

        public async Task<IGPDirectHttpResponse> SendAsync(
            HttpMethod method,
            Uri uri,
            string bearerToken,
            string? body,
            CancellationToken cancellationToken)
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            throw new PlatformNotSupportedException("IGP Core direct API does not support Unity WebGL");
#else
            using var request = new HttpRequestMessage(method, uri);
            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            if (!string.IsNullOrWhiteSpace(bearerToken))
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
            }

            if (body != null)
            {
                request.Content = new StringContent(body, Encoding.UTF8, "application/json");
            }

            using var response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
            var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            return new IGPDirectHttpResponse((int)response.StatusCode, responseBody);
#endif
        }

        public void Dispose()
        {
            client.Dispose();
        }
    }

    internal static class IGPDirectApiEnvironment
    {
        internal const string ProductionApiBaseUrl = "https://www.indiegp.cn/api";
        internal const string DevelopmentApiBaseUrl = "http://localhost:3001";

        internal static string ResolveBaseUrl(
            IGPSDKEnvironment environment,
            string? developmentOverride)
        {
            if (environment == IGPSDKEnvironment.DEV && !string.IsNullOrWhiteSpace(developmentOverride))
            {
                return NormalizeAbsoluteHttpUrl(developmentOverride!, "Curio API URL");
            }

            return environment == IGPSDKEnvironment.DEV
                ? DevelopmentApiBaseUrl
                : ProductionApiBaseUrl;
        }

        internal static string NormalizeAbsoluteHttpUrl(string value, string displayName)
        {
            var normalized = (value ?? string.Empty).Trim().TrimEnd('/');
            if (!Uri.TryCreate(normalized, UriKind.Absolute, out var uri) ||
                (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) ||
                !string.IsNullOrEmpty(uri.UserInfo) ||
                normalized.IndexOf('?') >= 0 ||
                normalized.IndexOf('#') >= 0 ||
                !string.IsNullOrEmpty(uri.Query) ||
                !string.IsNullOrEmpty(uri.Fragment))
            {
                throw new IGPSDKException(
                    displayName + " must use HTTP or HTTPS without credentials, query, or fragment",
                    Models.IGPErrorCodes.ERR_DIRECT_API_URL_INVALID);
            }

            return normalized;
        }
    }
}
