using Microsoft.AspNetCore.Mvc;
using Nop.Core;
using Nop.Core.Domain.Media;
using Nop.Core.Http.Extensions;
using Nop.Core.Infrastructure;
using Nop.Services.Media;
using ILogger = Nop.Services.Logging.ILogger;

namespace Nop.Web.Areas.Admin.Controllers;

public partial class DownloadController : BaseAdminController
{
    #region Fields

    protected readonly IDownloadService _downloadService;
    protected readonly ILogger _logger;
    protected readonly INopFileProvider _fileProvider;
    protected readonly IWorkContext _workContext;

    #endregion

    #region Ctor

    public DownloadController(IDownloadService downloadService,
        ILogger logger,
        INopFileProvider fileProvider,
        IWorkContext workContext)
    {
        _downloadService = downloadService;
        _logger = logger;
        _fileProvider = fileProvider;
        _workContext = workContext;
    }

    #endregion

    #region Methods

    public virtual async Task<IActionResult> DownloadFile(Guid downloadGuid)
    {
        var download = await _downloadService.GetDownloadByGuidAsync(downloadGuid);
        if (download == null)
            return Content("No download record found with the specified id");

        //A warning (SCS0027 - Open Redirect) from the "Security Code Scan" analyzer may appear at this point. 
        //In this case, it is not relevant. Url may not be local.
        if (download.UseDownloadUrl)
            return new RedirectResult(download.DownloadUrl);

        //use stored data
        if (download.DownloadBinary == null)
            return Content($"Download data is not available any more. Download GD={download.Id}");

        var fileName = !string.IsNullOrWhiteSpace(download.Filename) ? download.Filename : download.Id.ToString();
        var contentType = !string.IsNullOrWhiteSpace(download.ContentType)
            ? download.ContentType
            : MimeTypes.ApplicationOctetStream;
        return new FileContentResult(download.DownloadBinary, contentType)
        {
            FileDownloadName = fileName + download.Extension
        };
    }

    [HttpPost]
    public virtual async Task<IActionResult> SaveDownloadUrl(string downloadUrl)
    {
        //don't allow to save empty download object
        if (string.IsNullOrEmpty(downloadUrl))
        {
            return Json(new
            {
                success = false,
                message = "Please enter URL"
            });
        }

        //insert
        var download = new Download
        {
            DownloadGuid = Guid.NewGuid(),
            UseDownloadUrl = true,
            DownloadUrl = downloadUrl,
            IsNew = true
        };
        await _downloadService.InsertDownloadAsync(download);

        return Json(new { success = true, downloadId = download.Id });
    }

    [HttpPost]
    //do not validate request token (XSRF)
    [IgnoreAntiforgeryToken]
    public virtual async Task<IActionResult> AsyncUpload()
    {
        var httpPostedFile = await Request.GetFirstOrDefaultFileAsync();
        if (httpPostedFile == null)
        {
            return Json(new
            {
                success = false,
                message = "No file uploaded"
            });
        }

        var fileBinary = await _downloadService.GetDownloadBitsAsync(httpPostedFile);

        var fileName = httpPostedFile.FileName;

        //remove path (passed in IE)
        fileName = _fileProvider.GetFileName(fileName);

        var contentType = httpPostedFile.ContentType;

        var fileExtension = _fileProvider.GetFileExtension(fileName);
        if (!string.IsNullOrEmpty(fileExtension))
            fileExtension = fileExtension.ToLowerInvariant();

        var download = new Download
        {
            DownloadGuid = Guid.NewGuid(),
            UseDownloadUrl = false,
            DownloadUrl = string.Empty,
            DownloadBinary = fileBinary,
            ContentType = contentType,
            //we store filename without extension for downloads
            Filename = _fileProvider.GetFileNameWithoutExtension(fileName),
            Extension = fileExtension,
            IsNew = true
        };

        try
        {
            await _downloadService.InsertDownloadAsync(download);

            //when returning JSON the mime-type must be set to text/plain
            //otherwise some browsers will pop-up a "Save As" dialog.
            return Json(new
            {
                success = true,
                downloadId = download.Id,
                downloadUrl = Url.Action("DownloadFile", new { downloadGuid = download.DownloadGuid })
            });
        }
        catch (Exception exc)
        {
            await _logger.ErrorAsync(exc.Message, exc, await _workContext.GetCurrentCustomerAsync());

            return Json(new
            {
                success = false,
                message = "File cannot be saved"
            });
        }
    }

    #endregion
}