using FluentValidation.AspNetCore;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Performance.Api.Controllers
{
    [Route("api/[controller]")]
    public class TemplateController : Controller
    {
        private readonly TemplateService templateService;
        private readonly DFExtractService extractService;
        private HospitalService hospitalService;
        private IHostingEnvironment env;
        private ClaimService claim;
        private Application application;
        private WebapiUrl url;
        private readonly AllotService allotService;
        private readonly LogManageService logService;
        private readonly ILogger<ExceptionsFilter> logger;

        public TemplateController(TemplateService templateService,
            HospitalService hospitalService,
            DFExtractService extractService,
            IHostingEnvironment env,
            ClaimService claim,
            IOptions<Application> options,
            IOptions<WebapiUrl> url,
            AllotService allotService,
            LogManageService logService,
            ILogger<ExceptionsFilter> logger)
        {
            this.templateService = templateService;
            this.extractService = extractService;
            this.hospitalService = hospitalService;
            this.env = env;
            this.claim = claim;
            this.application = options.Value;
            this.url = url.Value;
            this.allotService = allotService;
            this.logService = logService;
            this.logger = logger;
        }

        /// <summary>
        /// 从WebAPI下载模板 1、医院绩效模板  2、医院二次分配绩效模板 3、医院绩效模板(无执行科室)
        /// </summary>
        /// <returns></returns>
        [Route("downtemplate")]
        [HttpGet]
        [AllowAnonymous]
        public IActionResult DownFile(int type = 1)
        {
            string path = "";
            switch (type)
            {
                case 1:
                    path = Path.Combine(env.ContentRootPath, "Template", "医院绩效模板.xls");
                    break;
                case 2:
                    path = Path.Combine(env.ContentRootPath, "Template", "医院二次分配绩效模板.xlsx");
                    break;
                case 3:
                    path = Path.Combine(env.ContentRootPath, "Template", "医院绩效模板(无执行科室).xlsx");
                    break;
                case 4:
                    path = Path.Combine(env.ContentRootPath, "Template", "医院人员绩效模板.xls");
                    break;
            }

            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(path, FileMode.Open))
            {
                stream.CopyToAsync(memoryStream).Wait();
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            var provider = new FileExtensionContentTypeProvider();

            var memi = provider.Mappings[".xlsx"];
            return File(memoryStream, memi, Path.GetFileName(path));
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        [Route("import")]
        [HttpPost]
        public ApiResponse Import([FromForm] IFormCollection form)
        {
            var userId = claim.GetUserId();
            var hospitalid = form.ToDictionary().GetValue("hospitalid", 0);
            if (hospitalid <= 0)
                return new ApiResponse(ResponseType.Fail, "参数错误", "hospitalid无效");

            var file = ((FormFileCollection)form.Files).FirstOrDefault();
            if (file == null)
                return new ApiResponse(ResponseType.Fail, "参数错误", "文件无效");

            var hospital = hospitalService.GetHopital(hospitalid);
            if (hospital == null)
                return new ApiResponse(ResponseType.Fail, "hospitalid不存在");

            var name = FileHelper.GetFileNameNoExtension(file.FileName) + DateTime.Now.ToString("yyyyMMddHHmmssfff");
            var ext = FileHelper.GetExtension(file.FileName);
            var dpath = Path.Combine(env.ContentRootPath, "Files", $"{hospitalid}", "first");
            FileHelper.CreateDirectory(dpath);

            var path = Path.Combine(dpath, $"{name}{ext}");

            using (var stream = file.OpenReadStream())
            {
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                if (!FileHelper.CreateFile(path, bytes))
                    return new ApiResponse(ResponseType.Fail, $"{file.FileName}上传失败");
                var template = new per_first
                {
                    HospitalId = hospitalid,
                    CreateUser = userId,
                    CreateDate = DateTime.Now,
                    Path = path,
                    UploadDate = DateTime.Now,
                    Remark = "上传成功"
                };
                if (templateService.InsertFirst(template))
                {
                    templateService.SendEmail(application.Receiver.ToList(), path, $"{hospital.HosName}首次上传模板", "上传成功");
                }
            }
            return new ApiResponse(ResponseType.OK);
        }

        #region 老版提取
        ///// <summary>
        ///// 提取绩效数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //[Route("extractdata")]
        //[HttpPost]
        //public ApiResponse ExtractData([CustomizeValidator(RuleSet = "Template"), FromBody]AllotRequest request)
        //{
        //    try
        //    {
        //        var allot = allotService.GetAllot(request.ID);
        //        if (allot == null)
        //            return new ApiResponse(ResponseType.Fail, "该绩效无效");
        //        allot.IsExtracting = allot.IsExtracting ?? 0;
        //        if (allot.IsExtracting == 1)
        //            return new ApiResponse(ResponseType.Fail, "正在提取数据，请稍等。");

        //        var hospital = hospitalService.GetHopital(request.HospitalId.Value);
        //        if (hospital == null)
        //            return new ApiResponse(ResponseType.Fail, "医院无效");

        //        var email = claim.GetUserClaim(JwtClaimTypes.Mail);
        //        allot.IsExtracting = 1;
        //        allotService.Update(allot);
        //        string path = extractService.GetFilepath(hospital.ID, out int type);
        //        if (!string.IsNullOrEmpty(path) && type != 0)
        //        {
        //            //发送请求，返回路径
        //            string retJson = HttpHelper.HttpClient(url.ImportFirst + $"?type={type}&hospitalId={hospital.ID}&year={allot.Year}&month={allot.Month}", path);
        //            var ret = JsonHelper.Deserialize<ApiResponse>(retJson);
        //            if ((int)ret.State != 1)
        //                return new ApiResponse(ResponseType.Fail, "首次模板地址无效！");
        //            path = ret.Message;
        //        }

        //        string param = JsonHelper.Serialize(new
        //        {
        //            id = request.ID,
        //            hospitalId = hospital.ID,
        //            mail = email,
        //            path = path
        //        });

        //        HttpHelper.HttpPostNoRequest(url.ExtractData, param, true);
        //        //extractService.ExtractData(request.ID, user.Mail, hospital);
        //        //BackgroundJob.Enqueue(() => extractService.ExtractData(request.ID, user.Mail, hospital));
        //        return new ApiResponse(ResponseType.OK, "HIS绩效数据提取任务正在执行，稍后我们将以邮件的通知您！");
        //    }
        //    catch (Exception ex)
        //    {
        //        var allot = allotService.GetAllot(request.ID);
        //        if (allot != null)
        //        {
        //            allot.IsExtracting = 3;
        //            allotService.Update(allot);
        //        }
        //        throw ex;
        //    }
        //}
        #endregion

        #region 新版提取
        /// <summary>
        /// 提取绩效数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("NewExtractData")]
        [HttpPost]
        public ApiResponse NewExtractData([CustomizeValidator, FromBody] ExtractRequest request)
        {
            var allot = allotService.GetAllot(request.AllotId);
            if (allot == null)
                return new ApiResponse(ResponseType.ParameterError, "AllotID错误");
            // 判断是那种抽取
            try
            {
                string message = extractService.Judge(request.AllotId, request.HospitalId, request.UseScheme, out string filePath);
                if (!string.IsNullOrEmpty(message))
                    return new ApiResponse(ResponseType.Fail, message);

                allot.IsExtracting = allot.IsExtracting ?? 0;
                if (allot.IsExtracting == 1)
                    return new ApiResponse(ResponseType.OK, "正在提取数据，请稍等！", new { IsExtracting = true });
                allot.IsExtracting = 1;
                allotService.Update(allot);

                //request.Email = claim.GetUserClaim(JwtClaimTypes.Mail);
                logger.LogInformation("提取绩效数据请求路径：" + url.HttpPost + "/extract/extract");
                //HttpHelper.HttpPostNoRequest(url.HttpPost + "/extract/extract", JsonHelper.Serialize(request), true);

                if (string.IsNullOrEmpty(filePath))
                    HttpHelper.HttpPostNoRequest(url.HttpPost + $"/extract/extract?allotId={request.AllotId}&hospitalId={request.HospitalId}&email={claim.GetUserClaim(JwtClaimTypes.Mail)}&userId={claim.GetUserId()}", "");
                else
                    HttpHelper.HttpClient(url.HttpPost + $"/extract/extract?allotId={request.AllotId}&hospitalId={request.HospitalId}&email={claim.GetUserClaim(JwtClaimTypes.Mail)}&userId={claim.GetUserId()}", filePath, true);

                return new ApiResponse(ResponseType.OK, "HIS绩效数据提取任务正在执行，稍后我们将以邮件的通知您！", new { IsExtracting = false });
            }
            catch (Exception ex)
            {
                if (allot != null)
                {
                    allot.IsExtracting = 3;
                    allotService.Update(allot);
                }
                logger.LogError("提取绩效数据:" + ex.ToString());
                throw new Exception(ex.Message);
            }
            // A 使用上传绩效作为模板
            // A-1 判断上传绩效是否存在，并执行成功
            // A-2 医院人员名单、1.0.1 额外收入（写出列头）、2.1 成本支出统计表（写出列头）、4.1 临床科室医护绩效测算表、4.2 特殊核算单元绩效测算表（数量、考核得分率、奖罚、其他）
            // A-3 收入 根据收入配置sheet名称获取抽取SQL，执行填充结果
            // A-4 工作量 根据配置项获取抽取SQL，执行填充结果

            // B 使用配置作为模板
        }
        #endregion


        /// <summary>
        /// 从WebAPI下载文件
        /// </summary>
        /// <returns></returns>
        [Route("down")]
        [AllowAnonymous]
        [HttpGet]
        public IActionResult DownFile([FromQuery] AllotRequest request)
        {
            var allot = allotService.GetAllot(request.ID);
            if (allot == null || string.IsNullOrWhiteSpace(allot.ExtractPath) || !FileHelper.IsExistFile(allot.ExtractPath))
            {
                return new ObjectResult(new ApiResponse(ResponseType.Fail, "文件不存在"));
            }

            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(allot.ExtractPath, FileMode.Open))
            {
                stream.CopyToAsync(memoryStream).Wait();
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            string fileExt = Path.GetExtension(allot.ExtractPath);
            var provider = new FileExtensionContentTypeProvider();
            var memi = provider.Mappings[fileExt];
            return File(memoryStream, memi, Path.GetFileName(allot.ExtractPath));
        }

        /// <summary>
        /// 保存提取文件
        /// </summary>
        /// <param name="form"></param>
        /// <param name="allotId"></param>
        /// <param name="hospitalId"></param>
        /// <returns></returns>
        [Route("savefile")]
        [HttpPost]
        [AllowAnonymous]
        public ApiResponse SaveFile([FromForm] IFormCollection form, int allotId, int hospitalId)
        {
            logger.LogInformation($"保存提取文件请求参数：allotId：{allotId} hospitalId：{hospitalId}");
            try
            {
                var file = ((FormFileCollection)form.Files).FirstOrDefault();
                if (file == null)
                {
                    logger.LogError($"返回文件为空！");
                    return new ApiResponse(ResponseType.Error, "上传文件无效");
                }

                var dpath = Path.Combine(env.ContentRootPath, "Files", $"{hospitalId}", "autoextract");
                FileHelper.CreateDirectory(dpath);

                var path = Path.Combine(dpath, FileHelper.GetFileName(file.FileName));
                logger.LogInformation($"保存提取文件保存路径：" + path);

                using (var stream = file.OpenReadStream())
                {
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    if (!FileHelper.CreateFile(path, bytes))
                    {
                        logger.LogError($"保存提取文件保存失败");
                        return new ApiResponse(ResponseType.Error, "保存失败");
                    }
                }
                var allot = allotService.GetAllot(allotId);
                allot.ExtractPath = path;
                allot.IsExtracting = 2;
                if (string.IsNullOrEmpty(path) || !FileHelper.IsExistFile(path))
                {
                    logger.LogInformation($"保存提取文件文件未保存成功，保存文件不存在！");
                    return new ApiResponse(ResponseType.Fail, "上传成功！");
                }
                if (!allotService.Update(allot))
                {
                    logger.LogInformation($"保存提取文件更新文件路径失败！");
                    return new ApiResponse(ResponseType.Fail, "上传成功！");
                }
                return new ApiResponse(ResponseType.OK, "上传成功！");
            }
            catch (Exception ex)
            {
                logger.LogInformation($"保存提取文件异常{ex.ToString()}");
                logger.LogError($"保存提取文件保存失败：" + ex.ToString());
                return new ApiResponse(ResponseType.Error, ex.Message);
            }
        }

        /// <summary>
        /// 返回日志
        /// </summary>
        /// <param name="type">1 进度条 2 信息</param>
        /// <param name="tag"></param>
        /// <param name="message"></param>
        /// <param name="level"></param>
        /// <param name="groupName"></param>
        [Route("returnlog")]
        [HttpPost]
        [AllowAnonymous]
        public void ReturnLog(int type, string tag, string message, int level, string groupName)
        {
            logger.LogInformation("返回日志：" + JsonHelper.Serialize(new { type, tag, message, level, groupName }));
            if (type == 3)
            {
                logService.Schedule(groupName, ConvertHelper.To<decimal>(message), level);
            }
            else
            {
                logService.ExtractLog(groupName, tag, message, level);
            }
        }

        /// <summary>
        /// 返回日志
        /// </summary>
        [Route("extractlog")]
        [HttpPost]
        public ApiResponse ReturnLog([FromBody] log_dbug request)
        {
            var allot = allotService.GetAllot(request.AllotID.Value);
            if (null == allot)
                throw new PerformanceException("当前绩效记录不存在");
            var list = allotService.AllotLog(allot, 2);
            return new ApiResponse(ResponseType.OK, list);
        }

        /// <summary>
        /// 返回日志
        /// </summary>
        [Route("schedule")]
        [HttpPost]
        public ApiResponse Schedule([FromBody] log_dbug request)
        {
            var allot = allotService.GetAllot(request.AllotID.Value);
            if (null == allot)
                throw new PerformanceException("当前绩效记录不存在");
            var ratio = allotService.AllotLog(allot, 3)?.Max(t => ConvertHelper.TryDecimal(t.Message)) ?? 0;
            return new ApiResponse(ResponseType.OK, new { ratio });
        }
    }
}