using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine.Networking;

namespace IndieExchange
{
    internal sealed class HttpResult
    {
        public long status;
        public byte[] body;
        public bool Ok => status >= 200 && status < 300;
    }

    internal sealed class LimitedDownload : DownloadHandlerScript
    {
        private readonly MemoryStream stream = new MemoryStream();
        private readonly int limit;
        public bool exceeded;
        public LimitedDownload(int limit) : base(new byte[65536]) { this.limit = limit; }
        protected override bool ReceiveData(byte[] data, int length)
        {
            if (data == null || length == 0) return true;
            if (stream.Length + length > limit) { exceeded = true; return false; }
            stream.Write(data, 0, length);
            return true;
        }
        public byte[] Bytes() => stream.ToArray();
    }

    internal static class AdTransport
    {
        public static bool AllowedUrl(string value, bool allowHttp)
            => Uri.TryCreate(value, UriKind.Absolute, out var uri) &&
                string.IsNullOrEmpty(uri.UserInfo) &&
                (uri.Scheme == "https" || (allowHttp && uri.Scheme == "http"));

        public static bool StoreUrl(string value)
        {
            if (!Uri.TryCreate(value, UriKind.Absolute, out var uri) || uri.Scheme != "https" || !string.IsNullOrEmpty(uri.UserInfo)) return false;
            return (uri.Host == "play.google.com" && uri.AbsolutePath == "/store/apps/details") ||
                uri.Host == "apps.apple.com";
        }

        public static async Task<HttpResult> Send(string url, string json, int limit, int timeout, CancellationToken token)
        {
            try
            {
                using (var request = new UnityWebRequest(url, json == null ? "GET" : "POST"))
                {
                    var handler = new LimitedDownload(limit);
                    request.downloadHandler = handler;
                    request.timeout = timeout;
                    request.redirectLimit = 0;
                    if (json != null)
                    {
                        request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json));
                        request.SetRequestHeader("Content-Type", "application/json");
                    }
                    var op = request.SendWebRequest();
                    var watch = System.Diagnostics.Stopwatch.StartNew();
                    while (!op.isDone)
                    {
                        if (token.IsCancellationRequested || watch.Elapsed.TotalSeconds > timeout)
                        {
                            request.Abort();
                            return new HttpResult();
                        }
                        await Task.Yield();
                    }
                    if (token.IsCancellationRequested || handler.exceeded) return new HttpResult();
                    return new HttpResult { status = request.responseCode, body = handler.Bytes() };
                }
            }
            catch (Exception) { return new HttpResult(); } // Network failure must never escape into the game's fallback path.
        }
    }
}
