using System;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace CoolGameX
{
    /// <summary>Result of a CoolAPI HTTP call.</summary>
    public struct ApiResult
    {
        public bool Success;
        public long StatusCode;
        public string Body;
        public string Error;
    }

    /// <summary>
    /// Internal HTTP helper built on UnityWebRequest, with an awaiter so calls
    /// can be used with async/await on the Unity main thread.
    /// </summary>
    internal static class Net
    {
        /// <summary>Request timeout in seconds (applied to all calls).</summary>
        public static int TimeoutSeconds = 20;

        public static async Task<ApiResult> PostJson(string path, string json, bool auth = true)
        {
            CoolAPI.EnsureReady();
            var url = CoolAPI.ServerUrl + path;

            using var req = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
            var bytes = Encoding.UTF8.GetBytes(json ?? "{}");
            req.uploadHandler = new UploadHandlerRaw(bytes);
            req.downloadHandler = new DownloadHandlerBuffer();
            req.timeout = TimeoutSeconds;
            req.SetRequestHeader("Content-Type", "application/json");

            if (auth)
            {
                if (string.IsNullOrEmpty(CoolAPI.Token))
                    return new ApiResult { Success = false, Error = "Not authenticated" };
                req.SetRequestHeader("Authorization", "Bearer " + CoolAPI.Token);
            }

            await req.SendWebRequest();
            return ToResult(req);
        }

        public static async Task<ApiResult> Get(string path, bool auth = false)
        {
            CoolAPI.EnsureReady();
            using var req = UnityWebRequest.Get(CoolAPI.ServerUrl + path);
            req.timeout = TimeoutSeconds;
            if (auth && !string.IsNullOrEmpty(CoolAPI.Token))
                req.SetRequestHeader("Authorization", "Bearer " + CoolAPI.Token);

            await req.SendWebRequest();
            return ToResult(req);
        }

        private static ApiResult ToResult(UnityWebRequest req)
        {
            bool ok = req.result == UnityWebRequest.Result.Success;
            string body = req.downloadHandler?.text;

            CoolAPI.LastStatus = req.responseCode;
            // We "reached" the server unless it was a connection-level failure.
            CoolAPI.IsConnected = req.result != UnityWebRequest.Result.ConnectionError;
            if (!ok)
            {
                CoolAPI.LastError = $"HTTP {req.responseCode} {req.error} — {body}";
                Debug.LogWarning($"[CoolAPI] {req.method} {req.url} → {req.responseCode} {req.error} — {body}");
            }

            return new ApiResult
            {
                Success = ok,
                StatusCode = req.responseCode,
                Body = body,
                Error = ok ? null : req.error,
            };
        }
    }

    /// <summary>
    /// Makes UnityWebRequestAsyncOperation awaitable so we can `await req.SendWebRequest()`.
    /// </summary>
    internal static class UnityWebRequestAwaiterExtensions
    {
        public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation op)
            => new UnityWebRequestAwaiter(op);
    }

    internal struct UnityWebRequestAwaiter : INotifyCompletion
    {
        private readonly UnityWebRequestAsyncOperation _op;

        public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation op) { _op = op; }

        public bool IsCompleted => _op.isDone;

        public void OnCompleted(Action continuation)
        {
            _op.completed += _ => continuation();
        }

        public void GetResult() { }
    }
}
