using System.Threading;
using System.Threading.Tasks;
using RudderSdk.Core;
using RudderSdk.Core.Abstractions;
using UnityEngine.Networking;

namespace RudderSdk.Unity
{
  internal sealed class UnityUploadTransport : IUploadTransport
  {
    private const int DefaultTimeoutSeconds = 10;

    private readonly int _timeoutSeconds;

    public UnityUploadTransport(int timeoutSeconds = DefaultTimeoutSeconds)
    {
      _timeoutSeconds = timeoutSeconds > 0 ? timeoutSeconds : DefaultTimeoutSeconds;
    }

    public async Task PutAsync(string url, byte[] data, string contentType, CancellationToken cancellationToken = default)
    {
      using (var request = UnityWebRequest.Put(url, data ?? System.Array.Empty<byte>()))
      {
        if (!string.IsNullOrEmpty(contentType))
          request.SetRequestHeader("Content-Type", contentType);

        request.timeout = _timeoutSeconds;

        var operation = request.SendWebRequest();
        var completion = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
        operation.completed += _ => completion.TrySetResult(true);

        using (cancellationToken.Register(() =>
        {
          request.Abort();
          completion.TrySetCanceled(cancellationToken);
        }))
        {
          await completion.Task.ConfigureAwait(false);
        }

        if (request.result == UnityWebRequest.Result.ConnectionError)
        {
          throw new RudderNetworkException(request.error);
        }

        if (request.result == UnityWebRequest.Result.ProtocolError)
        {
          throw new RudderApiException(
            (int)request.responseCode,
            string.Empty,
            request.error + ": " + request.downloadHandler?.text);
        }
      }
    }
  }
}
