using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Buffers;

using lkfxdok.c;
//using System.Net.Http.Headers;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.WebUtilities;
using System.IO;
using System.Text.Json;

using LKFWSContracts;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Http;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace WebCoreDemo.Controllers
{

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            var factories = context.ValueProviderFactories;
            factories.RemoveType<FormValueProviderFactory>();
            factories.RemoveType<JQueryFormValueProviderFactory>();
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }

    [Route("api/[controller]")]
    [ApiController]
    public class LKFProcessor : ControllerBase
    {
        // GET: api/<LKFProcessor>
        [HttpGet]
        public ServerInfo Get()
        {
            var version = lkfxdok.c.LKFController.Version;
            var minYear = lkfxdok.c.LKFController.ModelljahrMinimum;
            var maxYear = lkfxdok.c.LKFController.ModelljahrMaximum;
            var s = HttpContext.Session;
            s.Set("connected", new byte[1] { 1 });
            return new ServerInfo { version = version, minimumModelYear = minYear, maximumModelYear = maxYear };
        }

        // GET api/<LKFProcessor>/5
        [HttpGet("rootPath")]
        public string Get(int id)
        {
            var s = HttpContext.Session;
            return new string (lkfxdok.c.LKFController.DataPath );
        }

        [HttpGet("resultFile")]
        public FileStreamResult GetResultFile ()
        {
            return Download(new LKFOutputDataFile());
        }

        [HttpGet("warningFile")]
        public FileStreamResult GetWarningFile()
        {
            return Download(new LKFOutputWarningFile());
        }

        [HttpGet("errorFile")]
        public FileStreamResult GetErrorFile()
        {
            return Download(new LKFOutputErrorFile());
        }

        [HttpGet("infoFile")]
        public FileStreamResult GetInfoFile()
        {
            return Download(new LKFOutputInfoFile());
        }




        private FileStreamResult Download(LKFOutputFile outputFile)
        {
            var session = LKFSession.GetCurrent(HttpContext);
            var stream = new MemoryStream();
            var streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
            session.lkfContextWithData.WriteFile(outputFile.FileType, streamWriter);
            stream.Seek(0, SeekOrigin.Begin);
            return File(stream, "text/plain; charset=utf-8"); // returns a FileStreamResult
        }

        // POST api/<LKFProcessor>
        [HttpPost("prepareData")]
        public PrepareDataResponse Post([FromBody] PrepareData prepareData)
        {
            var session = LKFSession.GetCurrent(HttpContext);
            return session.Prepare(prepareData);
        }

        // POST api/<LKFProcessor>
        [HttpPost("compute")]
        public ComputeResponse Post([FromBody] Compute computeRequest)
        {
            var session = LKFSession.GetCurrent(HttpContext);
            return session.Compute(computeRequest);
        }

         /// <summary>
        /// Action for upload large file
        /// </summary>
        /// <remarks>
        /// Request to this action will not trigger any model binding or model validation,
        /// because this is a no-argument action
        /// </remarks>
        /// <returns></returns>
        [HttpPost]
       // [DisableFormValueModelBinding]
        [RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
        [Route("sendrows")]
        public async Task<IActionResult> UploadLargeFile()
        {
            var request = HttpContext.Request; //as Microsoft.AspNetCore.Http.HttpRequest;

            //HttpRequestRewindExtensions.EnableBuffering(request);

            // validation of Content-Type
            // 1. first, it must be a form-data request
            // 2. a boundary should be found in the Content-Type
            if (!request.HasFormContentType ||
                !MediaTypeHeaderValue.TryParse(request.ContentType, out var mediaTypeHeader) ||
                string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
            {
                return new UnsupportedMediaTypeResult();
            }

            var session = LKFSession.GetCurrent(HttpContext);

            if (request.ContentLength != null)
            {
                int len = (int) request.ContentLength.Value;
                var buf = new byte[len];

                try
                {
                    int readLength;
                    int pos = 0;

                    do
                    {
                        try {
                            readLength = await request.Body.ReadAsync(buf, pos, len - pos, System.Threading.CancellationToken.None);
                        }
                        catch (Exception ex)
                        {
                            return BadRequest(ex.Message);
                        }
                        if (readLength == 0)
                        {
                            break;
                        }
                        pos += readLength;
                    } while (true);
                    session.lkfContextWithData.AddBuffer(buf);

                    return Ok();
                }
                catch (Exception ex)
                {
                    return BadRequest(ex.Message);
                }

            }


            try
            {
                var reader = new MultipartReader(mediaTypeHeader.Boundary.Value, request.Body);
/*
                System.IO.Pipelines.ReadResult res;
                do
                {
               //     res = await request.BodyReader.ReadAsync();

                    session.lkfContextWithData.AddBuffer(res.Buffer.ToArray());
                } while (!res.IsCompleted);
*/

                var section = await reader.ReadNextSectionAsync();

                // This sample try to get the first file from request and save it
                // Make changes according to your needs in actual use
                while (section != null)
                {
                    var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition,
                        out var contentDisposition);

                    if (hasContentDispositionHeader && contentDisposition.DispositionType.Equals("form-data") &&
                        !string.IsNullOrEmpty(contentDisposition.FileName.Value))
                    {
                        // Don't trust any file name, file extension, and file data from the request unless you trust them completely
                        // Otherwise, it is very likely to cause problems such as virus uploading, disk filling, etc
                        // In short, it is necessary to restrict and verify the upload
                        // Here, we just use the temporary folder and a random file name

                        // Get the temporary folder, and combine a random file name with it
                        var fileName = Path.GetRandomFileName();
                        var saveToPath = Path.Combine(Path.GetTempPath(), fileName);

                        using (var targetStream = System.IO.File.Create(saveToPath))
                        {
                            await section.Body.CopyToAsync(targetStream);
                        }

                        return Ok();
                    }

                    section = await reader.ReadNextSectionAsync();
                }

            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
            // If the code runs to this location, it means that no files have been saved
            return BadRequest("No files data in the request.");
        }

        // PUT api/<LKFProcessor>/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        // DELETE api/<LKFProcessor>/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}
