// Ignore Spelling: aes

using Hims.Api.Models.Patient;
using Hims.Api.Models;
using Hims.Api.Utilities;
using Hims.Domain.Helpers;
using Hims.Domain.Services;
using Hims.Shared.DataFilters;
using Hims.Shared.EntityModels;
using Hims.Shared.Library.Enums;
using Hims.Shared.UserModels.Common;
using Hims.Shared.UserModels.PackageModule;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Hims.Domain.Entities;
using Hims.Domain.Configurations;
using System.IO;
using Microsoft.AspNetCore.Authorization;

namespace Hims.Api.Controllers
{
    [Route("api/package-module")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class PackageModuleController : BaseController
    {
        private readonly IAESHelper aesHelper;
        private readonly IPackageModuleService packageModuleServices;
        private readonly IDocumentHelper documentHelper;
        private readonly IRunningEnvironment runningEnvironment;
        private readonly IFtpUploadHelper ftpUploadHelper;
        private readonly IAuditLogService auditLogServices;
        public PackageModuleController(IPackageModuleService packageModuleServices, IAESHelper aesHelper, IDocumentHelper documentHelper, IRunningEnvironment runningEnvironment, IFtpUploadHelper ftpUploadHelper, IAuditLogService auditLogServices)
        {
            this.packageModuleServices = packageModuleServices;
            this.aesHelper = aesHelper;
            this.documentHelper = documentHelper;
            this.runningEnvironment = runningEnvironment;
            this.ftpUploadHelper = ftpUploadHelper;
            this.auditLogServices = auditLogServices;
        }

        [HttpGet]
        [Route("fetch-locations")]
        public async Task<ActionResult> FetchLocationsAsync()
        {
            var result = await this.packageModuleServices.FetchLocationsAsync();
            return this.Success(result);
        }

        [HttpGet]
        [Route("fetch-charge-categories")]
        public async Task<ActionResult> FetchChargeCategoriesAsync(int chargeModuleTemplateId)
        {
            var result = await this.packageModuleServices.FetchChargeCategoriesAsync(chargeModuleTemplateId);
            return this.Success(result);
        }

        [HttpGet]
        [Route("fetch-charge-categories-with-total")]
        public async Task<ActionResult> FetchChargeCategoriesWithTotalAsync(int packageModuleId, int chargeModuleTemplateId, int locationId)
        {
            var result = await this.packageModuleServices.FetchChargeCategoriesWithTotalAsync(packageModuleId, chargeModuleTemplateId, locationId);
            return this.Success(result);
        }

        [HttpGet]
        [Route("fetch-modules")]
        public async Task<ActionResult> FetchModulesAsync(int chargeModuleTemplateId)
        {
            var result = await this.packageModuleServices.FetchModulesAsync(chargeModuleTemplateId);
            return this.Success(result);
        }

        [HttpGet]
        [Route("fetch-module-charges")]
        public async Task<ActionResult> FetchModuleChargesAsync(string modulesMasterIds, int locationId)
        {
            var result = await this.packageModuleServices.FetchModuleChargesAsync(modulesMasterIds, locationId);
            return this.Success(result);
        }

        [HttpPost]
        [Route("fetch-charge-details")]
        public async Task<ActionResult> FetchChargeModuleDetailsAsync([FromBody] ChargeModuleDetailsRequestModel request)
        {
            var result = await this.packageModuleServices.FetchChargeModuleDetailsAsync(request);
            return this.Success(result);
        }

        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchAsync([FromBody] PackageModuleFilterModel model)
        {
            var packages = await this.packageModuleServices.FetchAsync(model);
            foreach (var package in packages)
            {
                package.EncryptedPackageModuleId = this.aesHelper.Encode(package.PackageModuleId.ToString());
            }
            return this.Success(packages);
        }

        [HttpPost]
        [Route("fetch-package-details")]
        public async Task<ActionResult> FetchPackageDetailsAsync([FromBody] StringIdRequest model)
        {
            model.MainId = Convert.ToInt32(model.Id);
            if(!string.IsNullOrEmpty(model.SubId))
            {
                model.SubMainId = Convert.ToInt32(model.SubId);
            }
            var packages = await this.packageModuleServices.FetchPackageDetails(model);
            return this.Success(packages);
        }

        [HttpGet]
        [Route("view")]
        public async Task<ActionResult> ViewAsync(int packageModuleId)
        {
            var result = await this.packageModuleServices.ViewAsync(packageModuleId);
            if (result == null || result.PackageModule == null || result.PackageModule.PackageModuleId == 0)
                return this.BadRequest("No package found.");
            return this.Success(result);
        }

        [HttpGet]
        [Route("find")]
        public async Task<ActionResult> FindAsync(string id)
        {
            var packageModuleId = Convert.ToInt32(this.aesHelper.Decode(id));
            var result = await this.packageModuleServices.ViewAsync(packageModuleId);
            if (result == null || result.PackageModule == null || result.PackageModule.PackageModuleId == 0)
                return this.BadRequest("No package found.");
            return this.Success(result);
        }

        [HttpPost]
        [Route("modify")]
        public async Task<ActionResult> ModifyAsync([FromBody] ModifyPackageModuleRequest request)
        {
            int result;
            //string message;
            if (request.PackageModule.PackageModuleId == 0)
            {
                result = await this.packageModuleServices.AddAsync(request.PackageModule, request.PackageDetails);
            }
            else
            {
                result = await this.packageModuleServices.UpdateAsync(request.PackageModule, request.PackageDetails);
            }

            var auditLogModel = new AuditLogModel
            {
                AccountId = request.PackageModule.CreatedBy,
                LogTypeId = (int)LogTypes.PackageModule,
                LogFrom = (short)request.PackageModule.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"<b>{request.PackageModule.CreatedByName}</b> has {(request.PackageModule.PackageModuleId == 0 ? "Added" : "Updated")} the Package Module <b> {request.PackageModule.PackageName}</b>  successfully",
                LocationId = Convert.ToInt32(request.PackageModule.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);
            return this.Success(result);
        }

        [HttpPost]
        [Route("disable")]
        public async Task<ActionResult> DisableAsync([FromBody] PackageModuleModel model)
        {
            var result = await this.packageModuleServices.DisableAsync(model.PackageModuleId, model.CreatedBy);
            
            var auditLogModel = new AuditLogModel
            {
                AccountId = model.CreatedBy,
                LogTypeId = (int)LogTypes.PackageModule,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"<b>{model.CreatedByName}</b> has disable the Package Name <b> {model.PackageName}</b>  successfully",
                LocationId = Convert.ToInt32(model.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);
            return result switch
            {
                0 => ServerError(),
                -1 => Failed("This package is already being used, so the selected package module cannot be disabled."),
                _ => Success("Package module has been disabled successfully."),
            };
        }

        [HttpPost]
        [Route("enable")]
        public async Task<ActionResult> EnableAsync([FromBody] PackageModuleModel model)
        {
            var result = await this.packageModuleServices.EnableAsync(model.PackageModuleId, model.CreatedBy);

            var auditLogModel = new AuditLogModel
            {
                AccountId = model.CreatedBy,
                LogTypeId = (int)LogTypes.PackageModule,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"<b>{model.CreatedByName}</b> has enable the Package Name <b> {model.PackageName}</b>  successfully",
                LocationId = Convert.ToInt32(model.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);
            return result <= 0 ? this.ServerError() : this.Success("Package module has been enabled successfully.");
        }

        [HttpPost]
        [Route("delete")]
        public async Task<ActionResult> DeleteAsync([FromBody] PackageModuleModel model)
        {
            var result = await this.packageModuleServices.DeleteAsync(model.PackageModuleId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = model.CreatedBy,
                LogTypeId = (int)LogTypes.PackageModule,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"<b>{model.CreatedByName}</b> has deleted the Package Name <b> {model.PackageName}</b>  successfully",
                LocationId = Convert.ToInt32(model.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);
            return result switch
            {
                0 => ServerError(),
                -1 => Failed("This package module is already being used, so the selected package module cannot be deleted."),
                _ => Success("Package module has been deleted successfully."),
            };
        }


        [HttpPost]
        [Route("upload-package-document")]
        [Consumes("multipart/form-data")]
        [Produces("application/json")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> UploadDocumentAsyn([FromForm] PackageDocumentModel request, [FromHeader] LocationHeader header)
        {
            request = (PackageDocumentModel)EmptyFilter.Handler(request);
            var files = this.Request.Form.Files;
            if (files == null || files.Count == 0)
            {
                return this.BadRequest("We're sorry. There are no files to upload.");
            }
            if (files.Count > 10)
            {
                return this.BadRequest("Maximum of 10 files can be allowed to upload.");
            }
            var contentTypes = this.documentHelper.FetchContentTypes().ToList();
            if (!ListFilter.ContainsAll(contentTypes, files.Select(m => m.ContentType).Distinct()))
            {
                return this.Failed($"Only {string.Join(", ", contentTypes)} files are allowed.");
            }
            var docuemnts = new List<PackageDocumentModel>();
            var index = 0;
            foreach (var file in files)
            {
                var model = new PackageDocumentModel
                {
                    Description = request.Description,
                    DocumentName = index == 0 ? request.DocumentName : $"{request.DocumentName}_{index}",
                    UploadedBy = request.UploadedBy,
                    PackageModuleId = request.PackageModuleId,
                    ContentType = file.ContentType,
                    Size = file.Length
                };
                var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/PackageDocuments/{request.PackageModuleId}";
                try
                {
                    await this.ftpUploadHelper.CreateDirectory(filePath);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                var dbPath = $@"{model.DocumentName}_{DateTime.UtcNow.Ticks}{Path.GetExtension(file.FileName)}";
                filePath += $@"/{dbPath}";
                var uploadResponse = await this.ftpUploadHelper.UploadFromFileAsync(filePath, file);
                if (uploadResponse <= 0)
                {
                    return this.BadRequest();
                }
                model.ThumbnailUrl = this.documentHelper.GetThumbnail(file.ContentType);
                model.DocumentUrl = dbPath;
                docuemnts.Add(model);
                index++;
            }
            var response = await this.packageModuleServices.AddPackageDocumentAsync(docuemnts);
            var enumerable = response.ToList();
            if (!enumerable.Any())
            {
                return this.ServerError();
            }
            var auditLogModel = new AuditLogModel
            {
                AccountId = request.UploadedBy,
                LogTypeId = (int)LogTypes.PackageModule,
                LogFrom = (short)request.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"<b>{request.CreatedByName}</b> has uploaded the Document Name <b> {request.DocumentName}</b>  successfully",
                LocationId = Convert.ToInt32(request.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);
            return this.Success($"Package document{(files.Count > 0 ? "s" : string.Empty)} has been uploaded successfully.");
        }


        [HttpPost]
        [AllowAnonymous]
        [Route("fetch-package-document")]
        [Consumes("application/json")]
        [Produces("application/json")]
        [ProducesResponseType(typeof(List<PatientDocumentModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchAsync([FromBody] int packageModuleId)
        {
            var scanDocuments = await this.packageModuleServices.FetchPackageDocuments(packageModuleId);
            if (scanDocuments == null)
            {
                return this.ServerError();
            }
            return this.Success(scanDocuments);
        }
    }



    public class ModifyPackageModuleRequest
    {
        public PackageModuleModel PackageModule { get; set; }

        public List<PackageModuleDetailModel> PackageDetails { get; set; }

        public string RemovedPackageModuleDetailIds { get; set; }



    }
}