using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using Timeline.Models;
namespace Timeline.Formatters
{
    /// 
    /// Formatter that reads body as byte data.
    /// 
    public class ByteDataInputFormatter : InputFormatter
    {
        /// 
        /// 
        /// 
        public ByteDataInputFormatter()
        {
            SupportedMediaTypes.Add(MimeTypes.ImagePng);
            SupportedMediaTypes.Add(MimeTypes.ImageJpeg);
            SupportedMediaTypes.Add(MimeTypes.ImageGif);
            SupportedMediaTypes.Add(MimeTypes.ImageWebp);
            SupportedMediaTypes.Add(MimeTypes.TextPlain);
            SupportedMediaTypes.Add(MimeTypes.TextMarkdown);
        }
        /// 
        public override bool CanRead(InputFormatterContext context)
        {
            if (context == null) throw new ArgumentNullException(nameof(context));
            if (context.ModelType == typeof(ByteData))
                return true;
            return false;
        }
        /// 
        public override async Task ReadRequestBodyAsync(InputFormatterContext context)
        {
            var request = context.HttpContext.Request;
            var contentLength = request.ContentLength;
            var logger = context.HttpContext.RequestServices.GetRequiredService>();
            if (request.ContentType is null)
            {
                logger.LogInformation("Failed to read body as bytes. Content-Type is not set.");
                return await InputFormatterResult.FailureAsync();
            }
            if (contentLength == null)
            {
                logger.LogInformation("Failed to read body as bytes. Content-Length is not set.");
                return await InputFormatterResult.FailureAsync();
            }
            if (contentLength == 0)
            {
                logger.LogInformation("Failed to read body as bytes. Content-Length is 0.");
                return await InputFormatterResult.FailureAsync();
            }
            var bodyStream = request.Body;
            var data = new byte[contentLength.Value];
            var bytesRead = await bodyStream.ReadAsync(data);
            if (bytesRead != contentLength)
            {
                logger.LogInformation("Failed to read body as bytes. Actual length of body is smaller than Content-Length.");
                return await InputFormatterResult.FailureAsync();
            }
            var extraByte = new byte[1];
            if (await bodyStream.ReadAsync(extraByte) != 0)
            {
                logger.LogInformation("Failed to read body as bytes. Actual length of body is greater than Content-Length.");
                return await InputFormatterResult.FailureAsync();
            }
            return await InputFormatterResult.SuccessAsync(new ByteData(data, request.ContentType));
        }
    }
}