using System;
using System.IO;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FarmmapsApi.Models;
using Google.Apis.Http;
using Google.Apis.Json;
using Google.Apis.Requests;
using Google.Apis.Upload;
using Google.Apis.Util;
using Newtonsoft.Json;
namespace FarmmapsApi.Services
{
    public class FarmmapsUploader : ResumableUpload
    {
        /// Payload description headers, describing the content itself.
        private const string PayloadContentTypeHeader = "X-Upload-Content-Type";
        /// Payload description headers, describing the content itself.
        private const string PayloadContentLengthHeader = "X-Upload-Content-Length";
        private const int UnknownSize = -1;
        /// Gets or sets the service.
        private HttpClient HttpClient { get; }
        /// 
        /// Gets or sets the path of the method (combined with
        /// ) to produce 
        /// absolute Uri. 
        /// 
        private string Path { get; }
        /// Gets or sets the HTTP method of this upload (used to initialize the upload).
        private string HttpMethod { get; }
        /// Gets or sets the stream's Content-Type.
        private string ContentType { get; }
        /// Gets or sets the body of this request.
        private FileRequest Body { get; }
        private long _streamLength;
        /// 
        /// Create a resumable upload instance with the required parameters.
        /// 
        /// The stream containing the content to upload.
        /// 
        /// Caller is responsible for maintaining the  open until the upload is 
        /// completed.
        /// Caller is responsible for closing the .
        /// 
        public FarmmapsUploader(ConfigurableHttpClient httpClient, Stream contentStream, FileRequest body, string contentType, string path)
            : base(contentStream,
                new ResumableUploadOptions
                {
                    HttpClient = httpClient,
                    Serializer = new NewtonsoftJsonSerializer(),
                    ServiceName = "FarmMaps"
                })
        {
            httpClient.ThrowIfNull(nameof(httpClient));
            contentStream.ThrowIfNull(nameof(contentStream));
            
            _streamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize;
            var twoMB = 2 * 0x100000;
            ChunkSize = twoMB;
            body.ChunkSize = ChunkSize;
            Body = body;
            
            Path = path;
            HttpClient = httpClient;
            HttpMethod = HttpConsts.Post;
            ContentType = contentType;
        }
        /// 
        public override async Task InitiateSessionAsync(CancellationToken cancellationToken = default)
        {
            HttpRequestMessage request = CreateInitializeRequest();
            Options?.ModifySessionInitiationRequest?.Invoke(request);
            var response = await HttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
            if (!response.IsSuccessStatusCode)
            {
                throw await ExceptionForResponseAsync(response).ConfigureAwait(false);
            }
            return response.Headers.Location;
        }
        /// Creates a request to initialize a request.
        private HttpRequestMessage CreateInitializeRequest()
        {
            var builder = new RequestBuilder()
            {
                BaseUri = HttpClient.BaseAddress,
                Path = Path,
                Method = HttpMethod,
            };
            HttpRequestMessage request = builder.CreateRequest();
            if (ContentType != null)
            {
                request.Headers.Add(PayloadContentTypeHeader, ContentType);
            }
            // if the length is unknown at the time of this request, omit "X-Upload-Content-Length" header
            if (ContentStream.CanSeek)
            {
                request.Headers.Add(PayloadContentLengthHeader, _streamLength.ToString());
            }
            var jsonText = JsonConvert.SerializeObject(Body);
            request.Content = new StringContent(jsonText, Encoding.UTF8, MediaTypeNames.Application.Json);
            return request;
        }
    }
}