using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using wispro.sp.entity;
using wispro.sp.share;

namespace wispro.sp.api.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class AttachFilesController : ControllerBase
    {
        private readonly IWebHostEnvironment env;
        private readonly ILogger<AttachFilesController> logger;
        private readonly spDbContext Context;

        public AttachFilesController(IWebHostEnvironment env,
            ILogger<AttachFilesController> logger,spDbContext context)
        {
            this.env = env;
            this.logger = logger;
            this.Context = context;
        }

        private string GetContentType(string path)
        {
            var provider = new FileExtensionContentTypeProvider();
            string contentType;

            if (!provider.TryGetContentType(path, out contentType))
            {
                contentType = "application/octet-stream";
            }

            return contentType;
        }

        [HttpGet,DisableRequestSizeLimit]
        public async Task<IActionResult> Download(string Id)
        {
            var filename = Context.AttachFiles.Where<AttachFile>(a => a.Id == new Guid(Id)).FirstOrDefault();

            if (filename != null)
            {
                var attachfileSavePath = utility.ConfigHelper.GetSectionValue("AttachFileSavePath");
                var filePath = Path.Combine(attachfileSavePath,
                    filename.SavePath);

                var context = HttpContext;

                if (System.IO.File.Exists(filePath))
                {
                    var memory = new MemoryStream();
                    await using (var stream = new FileStream(filePath, FileMode.Open))
                    {
                        await stream.CopyToAsync(memory);
                    }
                    memory.Position = 0;
                    return File(memory, GetContentType(filename.Name), filename.Name);
                }
                else
                    return NotFound();
            }
            else
            {
                return NotFound();
            }
        }

        public async Task<bool> Delete(string Id)
        {
            var filename = Context.AttachFiles.Where<AttachFile>(a => a.Id == new Guid(Id)).FirstOrDefault();

            if (filename != null)
            {
                var attachfileSavePath = utility.ConfigHelper.GetSectionValue("AttachFileSavePath");
                var filePath = Path.Combine(attachfileSavePath,
                    filename.SavePath);

                Context.AttachFiles.Remove(filename);
                await Context.SaveChangesAsync();

                if (System.IO.File.Exists(filePath))
                {
                    System.IO.File.Delete(filePath);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        [HttpPost]
        public async Task<ActionResult<AttachFile>> PostFile(
        [FromForm] IEnumerable<IFormFile> files)
        {
            var maxAllowedFiles = 3;
            long maxFileSize = 1024 * 1024 * 15;
            var filesProcessed = 0;
            var resourcePath = new Uri($"{Request.Scheme}://{Request.Host}/");
            List<AttachFile> uploadResults = new();

            foreach (var file in files)
            {
                var attachFile = new AttachFile();
                string trustedFileNameForFileStorage;
                var untrustedFileName = file.FileName;
                attachFile.Name  = untrustedFileName;

                Staff uploadUser = Context.Staffs.Where<Staff>(s => s.Name == "何倚雯").FirstOrDefault();

                if (uploadUser != null)
                {
                    attachFile.UploadUserId = uploadUser.Id;
                }

                var trustedFileNameForDisplay =
                    WebUtility.HtmlEncode(untrustedFileName);

                if (filesProcessed < maxAllowedFiles)
                {
                    if (file.Length == 0)
                    {
                        logger.LogInformation("{FileName} length is 0 (Err: 1)",
                            trustedFileNameForDisplay);
                        //uploadResult.ErrorCode = 1;
                    }
                    else if (file.Length > maxFileSize)
                    {
                        logger.LogInformation("{FileName} of {Length} bytes is " +
                            "larger than the limit of {Limit} bytes (Err: 2)",
                            trustedFileNameForDisplay, file.Length, maxFileSize);
                        //uploadResult.ErrorCode = 2;
                    }
                    else
                    {
                        try
                        {
                            trustedFileNameForFileStorage = Path.GetRandomFileName();

                            var attachfileSavePath = utility.ConfigHelper.GetSectionValue("AttachFileSavePath");
                            var path = Path.Combine(attachfileSavePath,                                
                                trustedFileNameForFileStorage);

                            await using FileStream fs = new(path, FileMode.Create);
                            await file.CopyToAsync(fs);
                            attachFile.SavePath = path;

                            logger.LogInformation("{FileName} saved at {Path}",
                                trustedFileNameForDisplay, path);

                            Context.AttachFiles.Add(attachFile);
                            Context.SaveChanges();
                            //uploadResult.Uploaded = true;
                            //uploadResult.StoredFileName = trustedFileNameForFileStorage;
                        }
                        catch (IOException ex)
                        {
                            logger.LogError("{FileName} error on upload (Err: 3): {Message}",
                                trustedFileNameForDisplay, ex.Message);
                            //uploadResult.ErrorCode = 3;
                        }
                    }

                    filesProcessed++;
                }
                else
                {
                    logger.LogInformation("{FileName} not uploaded because the " +
                        "request exceeded the allowed {Count} of files (Err: 4)",
                        trustedFileNameForDisplay, maxAllowedFiles);
                    //uploadResult.ErrorCode = 4;
                }

                uploadResults.Add(attachFile);
            }

            return new CreatedResult(resourcePath, uploadResults);
        }
    }
}
