using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using AyaNova.Models;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Biz;
using System.Threading.Tasks;
using AyaNova.Util;
using System;
using Microsoft.AspNetCore.Http;




namespace AyaNova.Api.Controllers
{


    /// <summary>
    /// Backup
    /// 
    /// </summary>
    [ApiController]
    [ApiVersion("8.0")]
    [Route("api/v{version:apiVersion}/backup")]
    [Produces("application/json")]
    public class BackupController : ControllerBase
    {
        private readonly AyContext ct;
        private readonly ILogger<BackupController> log;
        private readonly ApiServerState serverState;



        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbcontext"></param>
        /// <param name="logger"></param>
        /// <param name="apiServerState"></param>
        public BackupController(AyContext dbcontext, ILogger<BackupController> logger, ApiServerState apiServerState)
        {
            ct = dbcontext;
            log = logger;
            serverState = apiServerState;
        }

        //DANGER: MUST ADD AUTHORIZE ATTRIBUTE TO ANY NEW ROUTES
        //[Authorize]

        /// <summary>
        /// Trigger immediate system backup
        /// 
        /// </summary>        
        /// <returns>Job Id</returns>
        [HttpPost("backup-now")]
        [Authorize]
        public async Task<IActionResult> PostBackupNow()
        {
            if (serverState.IsClosed)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            if (!Authorized.HasModifyRole(HttpContext.Items, AyaType.Backup))//technically maybe this could be wider open, but for now keeping as locked down
                return StatusCode(403, new ApiNotAuthorizedResponse());
            var JobName = $"Backup (on demand)";
            OpsJob j = new OpsJob();
            j.Name = JobName;
            j.ObjectType = AyaType.NoType;
            j.JobType = JobType.Backup;
            j.SubType = JobSubType.NotSet;
            j.Exclusive = true;
            await JobsBiz.AddJobAsync(j);
            await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.ServerJob, AyaEvent.Created, JobName), ct);
            return Accepted(new { JobId = j.GId });
        }


        /// <summary>
        /// Get status of backup
        /// </summary>
        /// <returns></returns>            
        [HttpGet("status")]
        [Authorize]
        public ActionResult BackupStatus()
        {
            //Need size and more info
            if (serverState.IsClosed)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.Backup))
                return StatusCode(403, new ApiNotAuthorizedResponse());
            return Ok(ApiOkResponse.Response(FileUtil.BackupStatusReport()));
        }

        /// <summary>
        /// Download a backup file
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="t">download token</param>
        /// <returns></returns>
        [HttpGet("download/{fileName}")]
        public async Task<IActionResult> DownloadAsync([FromRoute] string fileName, [FromQuery] string t)
        {
          
            if (!serverState.IsOpen)
                return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
            var DownloadUser = await UserBiz.ValidateDownloadTokenAndReturnUserAsync(t, ct);
            if (DownloadUser == null)
            {
                await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//DOS protection
                return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED));
            }           

            if (!Authorized.HasModifyRole(DownloadUser.Roles, AyaType.Backup))//not technically modify but treating as such as a backup is very sensitive data
            {
                await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//DOS protection
                return StatusCode(403, new ApiNotAuthorizedResponse());
            }

            if (!FileUtil.BackupFileExists(fileName))
            {
                await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);//fishing protection
                return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
            }
            string mimetype = fileName.EndsWith("zip") ? "application/zip" : "application/octet-stream";
            var utilityFilePath = FileUtil.GetFullPathForBackupFile(fileName);
            await EventLogProcessor.LogEventToDatabaseAsync(new Event(DownloadUser.Id, 0, AyaType.NoType, AyaEvent.UtilityFileDownload, fileName), ct);
            return PhysicalFile(utilityFilePath, mimetype, fileName);

        }


        //DANGER: MUST ADD AUTHORIZE ATTRIBUTE TO ANY NEW ROUTES
        //[Authorize]

    }//eoc
}//eons
