using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Performance.Services.AllotCompute
{
    public class CheckDataService : IAutoInjection
    {
        private PerSheetService perSheetService;
        private PerforCofcheckRepository perforCofcheckRepository;
        private PerforLogcheckRepository perforLogcheckRepository;
        private PerforCofdrugtypeRepository perforCofdrugtypeRepository;
        private LogManageService logManageService;
        public CheckDataService(PerSheetService perSheetService,
            PerforCofcheckRepository perforCofcheckRepository,
            PerforLogcheckRepository perforLogcheckRepository,
            PerforCofdrugtypeRepository perforCofdrugtypeRepository,
            LogManageService logManageService
            )
        {
            this.perSheetService = perSheetService;
            this.perforCofcheckRepository = perforCofcheckRepository;
            this.perforLogcheckRepository = perforLogcheckRepository;
            this.perforCofdrugtypeRepository = perforCofdrugtypeRepository;
            this.logManageService = logManageService;
        }
        internal bool Check(PerExcel excel, per_allot allot)
        {
            bool result = true;
            //sheet页名称分类
            excel = Classify(excel, allot);

            //列头识别
            if (!Discern(excel, allot))
                result = false;

            //匹配绩效参考标准  
            //空行数据校验
            CheckData(excel, allot);

            //科室收入项 总费用相等 校验（暂不处理）

            return result;
        }

        #region sheet页名称分类
        /// <summary>
        /// sheet页名称分类
        /// </summary>
        /// <param name="excel"></param>
        /// <param name="allot"></param>
        /// <returns></returns>
        public PerExcel Classify(PerExcel excel, per_allot allot)
        {
            var perSheet = excel.PerSheet;
            foreach (var sheet in perSheet)
            {
                string message;
                bool flag = true;
                SheetType sheetType = perSheetService.GetSheetType(sheet.SheetName);
                if (sheetType != SheetType.Unidentifiable)
                    message = $"{sheet.SheetName} -- 已成功分类，类别为：{EnumHelper.GetDescription(sheetType)}；";
                else
                {
                    flag = false;
                    message = $"{sheet.SheetName} -- 未识别，请检测sheet页名称是否正确；";
                }
                InsertLog(allot.ID, (int)sheetType, flag ? 1 : 3, "sheet页名称分类", message);
            }
            return excel;
        }
        #endregion

        #region 列头识别
        /// <summary>
        /// 列头识别
        /// </summary>
        /// <param name="excel"></param>
        /// <returns></returns>
        public bool Discern(PerExcel excel, per_allot allot)
        {
            var result = true;
            var perSheet = excel.PerSheet;
            foreach (var sheet in perSheet)
            {
                var flag = true;
                string message = $"{sheet.SheetName} -- 列头符合要求；";
                var cellValue = sheet.PerHeader.Select(t => t.CellValue).ToList();
                foreach (var item in sheet.PerHeader)
                {
                    if (item.IsHasChildren)
                        cellValue = cellValue.Union(item.Children.Select(t => t.CellValue)).ToList();
                }
                var headerCheck = perforCofcheckRepository.GetEntities(t => t.Type == (int)sheet.SheetType)
                             ?.Select(t => t.CellName).Distinct().ToList();
                if (headerCheck != null)
                {
                    var list = cellValue.Intersect(headerCheck).ToList();  //求交集，提交的列头和数据库中保存的列头
                    var drugtype = perforCofdrugtypeRepository.GetEntities(t => t.AllotID == allot.ID);
                    if (drugtype != null && drugtype.Count > 0)
                        list = list.Union(drugtype.Select(t => t.Charge)).ToList(); //药占比的类型
                    var lack = headerCheck.Except(list).ToList();   //求差集，数据库中列头与交集
                    if (lack.Count > 0)
                    {
                        flag = false;
                        message = $"{sheet.SheetName} -- 列头不规范，缺少列头或命名不规范：“{String.Join("、", lack.ToArray())}”不存在；";
                    }
                    if (!flag)
                        result = false;
                }
                InsertLog(allot.ID, (int)sheet.SheetType, flag ? 1 : 3, "列头识别", message);
            }
            return result;
        }
        #endregion        

        #region 空行数据校验
        public bool CheckData(PerExcel excel, per_allot allot)
        {
            var result = true;
            var perSheet = excel.PerSheet;
            foreach (var sheet in perSheet)
            {
                string message = $"{sheet.SheetName} -- 数据符合规范；";
                List<int> rowNumber = new List<int>();
                bool flag = true;
                int count = 0;
                if (sheet.SheetName.StartsWith("医院人员名单"))
                {
                    List<string> accountType = new List<string>() { "临床科室", "医技科室", "行政工勤", "行政中高层", "" };
                    List<string> fitPeople = EnumHelper.GetItems<PerforType>().Select(t => t.Description).ToList();
                    var dataList = sheet.PerData.Select(t => (PerDataEmployee)t);
                    foreach (var item in dataList)
                    {
                        if (!accountType.Contains(item.AccountType) || !fitPeople.Contains(item.FitPeople) || string.IsNullOrEmpty(item.AccountingUnit))
                        {
                            flag = false;
                            rowNumber.Add(item.RowNumber + 1);
                            count++;
                        }
                    }
                }
                else if (sheet.SheetName.StartsWith("1.0") || sheet.SheetName.StartsWith("3."))
                {
                    var data = sheet.PerData.Select(t => (PerData)t);
                    var dataList = data.GroupBy(t => t.RowNumber).ToList();
                    foreach (var item in dataList)
                    {
                        var perData = item.FirstOrDefault();
                        if (string.IsNullOrEmpty(perData.AccountingUnit))
                        {
                            flag = false;
                            rowNumber.Add(perData.RowNumber + 1);
                            count++;
                        }
                    }
                }
                else if (sheet.SheetName.StartsWith("1.") || sheet.SheetName.StartsWith("2."))
                {
                    var data = sheet.PerData.Select(t => (PerData)t);
                    var dataList = data.GroupBy(t => t.RowNumber).ToList();
                    foreach (var item in dataList)
                    {
                        var doctor = item.Where(t => t.UnitType == "医生组").FirstOrDefault();
                        var nurse = item.Where(t => t.UnitType == "护理组").FirstOrDefault();
                        var technician = item.Where(t => t.UnitType == "医技组").FirstOrDefault();
                        if (string.IsNullOrEmpty(doctor?.AccountingUnit) && string.IsNullOrEmpty(nurse?.AccountingUnit) && string.IsNullOrEmpty(technician?.AccountingUnit))
                        {
                            flag = false;
                            rowNumber.Add(doctor.RowNumber + 1);
                            count++;
                        }
                    }
                }
                else if (sheet.SheetName.StartsWith("4.1"))
                {
                    var dataList = sheet.PerData.Select(t => (PerDataAccountBaisc)t);
                    foreach (var item in dataList)
                    {
                        if (string.IsNullOrEmpty(item.AccountingUnit))
                        {
                            flag = false;
                            rowNumber.Add(item.RowNumber + 1);
                            count++;
                        }
                    }
                }
                else if (sheet.SheetName.StartsWith("4.2"))
                {
                    var dataList = sheet.PerData.Select(t => (PerDataSpecialUnit)t);
                    foreach (var item in dataList)
                    {
                        if (string.IsNullOrEmpty(item.Department))
                        {
                            flag = false;
                            rowNumber.Add(item.RowNumber + 1);
                            count++;
                        }
                    }
                }

                if (!flag)
                {
                    result = false;
                    message = $"{sheet.SheetName} -- 有{count}行数据不合规范，行号是{String.Join("、", rowNumber.ToArray())}；";
                }
                InsertLog(allot.ID, (int)sheet.SheetType, flag ? 1 : 2, "空行数据校验", message.ToString());
            }
            return result;
        }
        #endregion

        #region 向log_check表中添加记录
        /// <summary>
        /// 向log_check表中添加记录
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="type">sheet_type</param>
        /// <param name="level">错误等级</param>
        /// <param name="title"></param>
        /// <param name="message">描述</param>
        public void InsertLog(int allotId, int type, int level, string title, string message)
        {
            log_check model = new log_check()
            {
                AllotID = allotId,
                CreateTime = DateTime.Now,
                Type = type,
                Level = level,
                Titile = title,
                Message = message
            };
            perforLogcheckRepository.Add(model);
            logManageService.WriteMsg("绩效数据校验", $"{title} - {message}", level, allotId, "ReceiveMessage", true);
        }
        #endregion
    }
}
