using AutoMapper;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.EntityModels.Entity;
using Performance.EntityModels.Other;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Repository.Repository;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Performance.Services
{
    public class AttendanceService : IAutoInjection
    {
        private readonly IMapper mapper;
        private readonly ILogger<AttendanceService> logger;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforPerAttendanceRepository perforPerAttendanceRepository;
        private readonly PerfoPperAttendanceTypeRepository perfoPperAttendanceTypeRepository;
        private readonly PerfoPperAttendanceVacationeRepository perfoPperAttendanceVacationeRepository;
        private readonly PerforPerdeptdicRepository perdeptdicRepository;
        private readonly PerforPeremployeeRepository perforPeremployeeRepository;
        private readonly PerforCofaccountingRepository cofaccountingRepository;
        public AttendanceService(
            IMapper mapper,
            ILogger<AttendanceService> logger,
            PerforPerallotRepository perforPerallotRepository,
            PerforPerAttendanceRepository perforPerAttendanceRepository,
            PerfoPperAttendanceTypeRepository perfoPperAttendanceTypeRepository,
            PerfoPperAttendanceVacationeRepository perfoPperAttendanceVacationeRepository,
            PerforPerdeptdicRepository perdeptdicRepository,
            PerforPeremployeeRepository perforPeremployeeRepository,
            PerforCofaccountingRepository cofaccountingRepository)
        {
            this.mapper = mapper;
            this.logger = logger;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforPerAttendanceRepository = perforPerAttendanceRepository;
            this.perfoPperAttendanceTypeRepository = perfoPperAttendanceTypeRepository;
            this.perfoPperAttendanceVacationeRepository = perfoPperAttendanceVacationeRepository;
            this.perdeptdicRepository = perdeptdicRepository;
            this.perforPeremployeeRepository = perforPeremployeeRepository;
            this.cofaccountingRepository = cofaccountingRepository;
        }

        #region 初始考勤页面

        public ApiResponse<List<AttendanceStatistics>> GetAttendance(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(w => w.ID == allotId);
            if (allot == null)
                throw new PerformanceException("当前绩效记录不存在");

            var attendanceData = perforPerallotRepository.GetAttendance(allotId);


            List<AttendanceStatistics> statistics = new List<AttendanceStatistics>();
            // 交叉补全科室结束时间
            foreach (var personnelNumber in attendanceData.Select(w => w.PersonnelNumber).Distinct())
            {
                var attendances = attendanceData.Where(w => w.PersonnelNumber == personnelNumber).OrderBy(w => w.AttendanceDate);
                for (int i = 0; i < attendances.Count() - 1; i++)
                {
                    var begDate = attendances.ElementAt(i).AttendanceDate.Date;
                    var endDate = attendances.ElementAt(i + 1).AttendanceDate.Date;
                    // 调入科室需要额外减去1天作为上一个科室结束时间
                    var days = attendances.ElementAt(i + 1).Source == Attendance.Type.调入.ToString() ? -1 : 0;
                    if (endDate > begDate)
                    {
                        var stat = new AttendanceStatistics
                        {
                            AllotID = attendances.ElementAt(i).ALLOTID,
                            UnitType = attendances.ElementAt(i).UnitType,
                            AccountingUnit = attendances.ElementAt(i).AccountingUnit,
                            Department = attendances.ElementAt(i).Department,
                            PersonnelNumber = attendances.ElementAt(i).PersonnelNumber,
                            PersonnelName = attendances.ElementAt(i).PersonnelName,
                            BeginDate = begDate,
                            EndDate = endDate.AddDays(days),
                            Detial = new List<AttendanceStatisticsDetial>()
                        };
                        statistics.Add(stat);
                    }
                }
            }
            if (statistics != null)
                return new ApiResponse<List<AttendanceStatistics>>(ResponseType.OK, statistics);
            else
            {
                return new ApiResponse<List<AttendanceStatistics>>(ResponseType.Fail);
            }
        }


        #endregion

        #region 调入记录
        public ApiResponse<List<view_attendance>> GetCallIn(int allotId)
        {
            var view_attendance = perforPerallotRepository.GetAttendance(allotId).Where(t => t.Source.Contains("调入")).ToList();

            if (view_attendance != null)
                return new ApiResponse<List<view_attendance>>(ResponseType.OK, view_attendance);
            else
            {
                return new ApiResponse<List<view_attendance>>(ResponseType.Fail);
            }

        }
        public HandsonTable GetBatchCallInHandsonTable(int allotId)
        {
            HandsonTable handson = new HandsonTable((int)SheetType.Unidentifiable, Person.Select(c => c.Item2).ToArray(), Person.Select(t => new collect_permission
            {
                HeadName = t.Item2,
                Visible = 1,
                Readnoly = 0
            }).ToList());
            if (handson.Columns != null && handson.Columns.Any())
            {
                var cofaccounting = cofaccountingRepository.GetEntities(w => w.UnitType != "" && w.AllotId == allotId);
                foreach (var column in handson.Columns)
                {
                    column.Type = "text";
                    if (column.Data == "调入组别")
                    {
                        column.Type = "autocomplete";
                        //column.Source = EnumHelper.GetItems<UnitType>().Select(w => w.Description.Replace("行政后勤", "行政工勤")).ToArray();
                        column.Source = cofaccounting.Select(w => w.UnitType).Distinct().ToArray();
                        column.Strict = true;
                    }

                    if (column.Data == "调入核算单元")
                    {
                        column.Type = "autocomplete";
                        //column.Source = EnumHelper.GetItems<AccountUnitType>().Where(w => w.Description != "").Select(w => w.Description).ToArray();
                        column.Source = cofaccounting.Select(w => w.AccountingUnit).Distinct().ToArray();
                        column.Strict = true;
                    }

                    //if (column.Data == "调入时间")
                    //{
                    //    column.Type = "date";
                    //    column.DateFormat = "YYYY/MM/DD";
                    //}
                }
            }
            List<view_attendance> data = new List<view_attendance>();
            data = GetCallIn(allotId).Data;

            var convertDate = data.Select(t =>
            new
            {
                t.PersonnelName,
                t.PersonnelNumber,
                t.AccountingUnit,
                t.UnitType,
                AttendanceDate = t.AttendanceDate.ToString("d")
            });
            if (convertDate == null)
                return handson;

            List<HandsonRowData> rowDatas = new List<HandsonRowData>();
            int i = 1;

            var dict = new Dictionary<string, string>();
            Person2.ForEach(t => dict.Add(t.Item1, t.Item2));

            foreach (var item in convertDate)
            {
                var json = JsonHelper.Serialize(item);
                var firstDic = JsonHelper.Deserialize<Dictionary<string, string>>(json);

                var cells = (from conf in dict join fst in firstDic on conf.Key.ToUpper() equals fst.Key.ToUpper() select new HandsonCellData(conf.Value, fst.Value)).ToList();

                rowDatas.Add(new HandsonRowData(i, cells));
                i++;
            }
            handson.SetRowData(rowDatas, rowDatas != null);
            foreach (var item in handson.Data)
            {
                item.Remove("编号");
            }
            return handson;
        }

        public ApiResponse BatchCallIn(int allotId, int hospitalId, SaveCollectData request)
        {
            var dict = new Dictionary<string, string>();
            Person.ForEach(t => dict.Add(t.Item1, t.Item2));

            var dicData = CreateDataRow(request, dict);
            if (dicData == null || dicData.Count == 0)
                return new ApiResponse(ResponseType.Error, "空数据，无效操作");

            var convertDicData = dicData.Select(w => new per_attendance
            {
                PersonnelNumber = w["PersonnelNumber"],
                PersonnelName = w["PersonnelName"],
                CallInAccountingUnit = w["CallInAccountingUnit"],
                CallInUnitType = w["CallInUnitType"],
                CallInDate = ConvertHelper.To<DateTime>(w["CallInDate"]),
            });

            var jsons = JsonHelper.Serialize(convertDicData);
            var newAttendanceVacatione = JsonHelper.Deserialize<List<per_attendance>>(jsons);
            var oldCallinAttendance = perforPerAttendanceRepository.GetEntities(t => t.AllotId == allotId && t.HospitalId == hospitalId);

            var per_allot = perforPerallotRepository.GetEntities(t => t.ID == allotId && t.HospitalId == hospitalId).FirstOrDefault();

            if (per_allot == null) return new ApiResponse(ResponseType.Error, "无绩效数据");

            var cofaccounting = cofaccountingRepository.GetEntities(ca => ca.AllotId == allotId);

            var per_employee = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId && t.HospitalId == hospitalId);

            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            for (int i = 0; i < newAttendanceVacatione.Count; i++)
            {

                if (string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelName?.Trim())
                    || string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelNumber?.Trim())
                    || string.IsNullOrEmpty(newAttendanceVacatione[i].CallInAccountingUnit?.Trim())
                    || string.IsNullOrEmpty(newAttendanceVacatione[i].CallInUnitType?.Trim())
                    || newAttendanceVacatione[i].CallInDate == null)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "调入核算单元", newAttendanceVacatione[i].CallInAccountingUnit??"" },
                        { "调入组别", newAttendanceVacatione[i].CallInUnitType??"" },
                        { "调入时间", newAttendanceVacatione[i].CallInDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "“关键信息缺失”请补全或删除" },
                    });
                }
                DateTime dt = new DateTime(per_allot.Year, per_allot.Month, 1).AddMonths(1);
                if (newAttendanceVacatione[i].CallInDate > dt)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "调入核算单元", newAttendanceVacatione[i].CallInAccountingUnit??"" },
                        { "调入组别", newAttendanceVacatione[i].CallInUnitType??"" },
                        { "调入时间", newAttendanceVacatione[i].CallInDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "调入时间不在当前绩效月份范围内" },
                    });
                }

                if (newAttendanceVacatione[i].CallInUnitType != cofaccounting.FirstOrDefault(t => t.AccountingUnit == newAttendanceVacatione[i].CallInAccountingUnit)?.UnitType)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "调入核算单元", newAttendanceVacatione[i].CallInAccountingUnit??"" },
                        { "调入组别", newAttendanceVacatione[i].CallInUnitType??"" },
                        { "调入时间", newAttendanceVacatione[i].CallInDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "该核算单元的调入组别不一致或不存在" },
                    });
                }

                if (newAttendanceVacatione[i].PersonnelName != per_employee.FirstOrDefault(t => t.PersonnelNumber == newAttendanceVacatione[i].PersonnelNumber && t.AllotId == allotId && t.HospitalId == hospitalId)?.DoctorName)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "调入核算单元", newAttendanceVacatione[i].CallInAccountingUnit??"" },
                        { "调入组别", newAttendanceVacatione[i].CallInUnitType??"" },
                        { "调入时间", newAttendanceVacatione[i].CallInDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "该人员与人员字典不一致或不存在" },
                    });
                }
                var oldEmp = oldCallinAttendance.FirstOrDefault(w => w.PersonnelNumber == newAttendanceVacatione[i].PersonnelNumber);
                if (!string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelName) && oldEmp != null && oldEmp.PersonnelName != newAttendanceVacatione[i].PersonnelName)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "调入核算单元", newAttendanceVacatione[i].CallInAccountingUnit??"" },
                        { "调入组别", newAttendanceVacatione[i].CallInUnitType??"" },
                        { "调入时间", newAttendanceVacatione[i].CallInDate.ToString()??"" },
                        { "来源", "“粘贴数据”与“历史数据”比对" },
                        { "错误原因", $"原名“{oldEmp.PersonnelName}”,工号相同但姓名不同,请删除“历史数据”中该员工" },
                    });
                }
            }
            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            List<per_attendance> addPer_Attendances = new List<per_attendance>();

            foreach (var data in newAttendanceVacatione)
            {
                data.AllotId = allotId;
                data.HospitalId = hospitalId;
                addPer_Attendances.Add(data);
                var any = oldCallinAttendance.FirstOrDefault(w => w.AllotId == allotId && w.HospitalId == hospitalId && w.CallInDate == data.CallInDate && w.CallInAccountingUnit?.Trim() == data.CallInAccountingUnit?.Trim() && w.CallInUnitType?.Trim() == data.CallInUnitType?.Trim() && w.PersonnelName?.Trim() == data.PersonnelName?.Trim() && w.PersonnelNumber?.Trim() == data.PersonnelNumber?.Trim());
            }

            perforPerAttendanceRepository.RemoveRange(oldCallinAttendance.ToArray());
            if (addPer_Attendances != null && addPer_Attendances.Any())
                perforPerAttendanceRepository.AddRange(addPer_Attendances.ToArray());

            return new ApiResponse(ResponseType.OK, "");

        }

        #endregion

        #region 考勤类型

        public ApiResponse<List<per_attendance_type>> GetAttendanceType(int allotId)
        {
            var result = perfoPperAttendanceTypeRepository.GetEntities(t => t.AllotId == allotId).ToList();
            if (result != null)
                return new ApiResponse<List<per_attendance_type>>(ResponseType.OK, result);
            else
            {
                return new ApiResponse<List<per_attendance_type>>(ResponseType.Fail);

            }
        }
        public ApiResponse<AttendanceType> InsertAttendanceType(int allotId, int hospitalId, AttendanceType attendanceType)
        {
            var any = perfoPperAttendanceTypeRepository.GetEntities().FirstOrDefault(t => t.Id == attendanceType.Id);
            if (any != null)
            {
                any.AttendanceName = attendanceType.AttendanceName;
                any.IsDeduction = Convert.ToInt32(attendanceType.IsDeduction);
                if (perfoPperAttendanceTypeRepository.Update(any)) return new ApiResponse<AttendanceType>(ResponseType.OK, "修改成功");
                else return new ApiResponse<AttendanceType>(ResponseType.Fail, "修改失败");

            }
            else
            {
                per_attendance_type per_Attendance_Type = new per_attendance_type()
                {
                    AllotId = allotId,
                    HospitalId = hospitalId,
                    AttendanceName = attendanceType.AttendanceName,
                    IsDeduction = Convert.ToInt32(attendanceType.IsDeduction)
                };
                if (perfoPperAttendanceTypeRepository.Add(per_Attendance_Type)) return new ApiResponse<AttendanceType>(ResponseType.OK, "添加成功");
                else return new ApiResponse<AttendanceType>(ResponseType.Fail, "添加失败");
            }

        }
        public ApiResponse DeleteAttendanceType(int id)
        {
            var any = perfoPperAttendanceTypeRepository.GetEntity(t => t.Id == id);

            if (any == null) return new ApiResponse(ResponseType.Fail, "没有该数据");

            var use = perfoPperAttendanceVacationeRepository.GetEntity(t => t.TypeId == any.Id);
            if (use != null) return new ApiResponse(ResponseType.Fail, "该类型正在使用！");

            if (any != null && use == null)
            {
                if (perfoPperAttendanceTypeRepository.DeleteFromQuery(t => t.Id == id) > 0) return new ApiResponse(ResponseType.OK, "删除成功");
                else return new ApiResponse(ResponseType.Fail, "删除失败");
            }
            else return new ApiResponse(ResponseType.Fail, "删除失败");
        }
        #endregion

        #region 考勤记录
        public HandsonTable GetAttendanceVacationHandsonTable(int allotId)
        {
            HandsonTable handson = new HandsonTable((int)SheetType.Unidentifiable, Vacation.Select(c => c.Item2).ToArray(), Vacation.Select(t => new collect_permission
            {
                HeadName = t.Item2,
                Visible = 1,
                Readnoly = 0
            }).ToList());
            if (handson.Columns != null && handson.Columns.Any())
            {
                var type = perfoPperAttendanceTypeRepository.GetEntities(t => t.AllotId == allotId);
                foreach (var column in handson.Columns)
                {
                    column.Type = "text";
                    //if (column.Data.Contains("时间"))
                    //{
                    //    column.Type = "date";
                    //    column.DateFormat = "YYYY/MM/DD";
                    //}
                    if (column.Data == "考勤类型")
                    {
                        column.Type = "autocomplete";
                        column.Source = type.Select(t => t.AttendanceName).ToArray();
                    }
                }
            }

            List<RecordAttendcance> data = new List<RecordAttendcance>();
            data = GetAttendanceVacation(allotId).Data;

            var convertDate = data.Select(t =>
            new
            {
                t.PersonnelName,
                t.PersonnelNumber,
                t.AttendanceName,
                BegDate = t.BegDate > DateTime.MinValue ? t.BegDate.ToString("d") : t.BegDate.ToString(),
                EndDate = t.EndDate > DateTime.MinValue ? t.EndDate.ToString("d") : t.EndDate.ToString()
            });
            if (convertDate == null)
                return handson;

            List<HandsonRowData> rowDatas = new List<HandsonRowData>();
            int i = 1;

            var dict = new Dictionary<string, string>();
            Vacation.ForEach(t => dict.Add(t.Item1, t.Item2));

            foreach (var item in convertDate)
            {
                var json = JsonHelper.Serialize(item);
                var firstDic = JsonHelper.Deserialize<Dictionary<string, string>>(json);

                var cells = (from conf in dict join fst in firstDic on conf.Key.ToUpper() equals fst.Key.ToUpper() select new HandsonCellData(conf.Value, fst.Value)).ToList();

                rowDatas.Add(new HandsonRowData(i, cells));
                i++;
            }
            handson.SetRowData(rowDatas, rowDatas != null);
            foreach (var item in handson.Data)
            {
                item.Remove("编号");
            }

            return handson;
        }

        public ApiResponse<List<RecordAttendcance>> GetAttendanceVacation(int allotId)
        {
            var vacatione = perfoPperAttendanceVacationeRepository.GetEntities(t => t.AllotId == allotId);
            var type = perfoPperAttendanceTypeRepository.GetEntities(t => t.AllotId == allotId);
            if (type.Count == 0)
                return new ApiResponse<List<RecordAttendcance>>(ResponseType.Fail, new List<RecordAttendcance>());

            var data = from a in vacatione
                       join b in type on a.TypeId equals b.Id into temp
                       from tt in temp.DefaultIfEmpty()
                       select new RecordAttendcance
                       {
                           Id = a.Id,
                           AllotId = a.AllotId,
                           HospitalId = a.HospitalId,
                           PersonnelName = a.PersonnelName,
                           PersonnelNumber = a.PersonnelNumber,
                           AttendanceName = tt.AttendanceName,
                           TypeId = a.TypeId,
                           BegDate = a.BegDate,
                           EndDate = a.EndDate,
                           Days = SplitEveryDay(ConvertHelper.To<DateTime>(a.BegDate), ConvertHelper.To<DateTime>(a.EndDate)).Count()
                       };
            if (data != null)
                return new ApiResponse<List<RecordAttendcance>>(ResponseType.OK, data.ToList());
            else
            {
                return new ApiResponse<List<RecordAttendcance>>(ResponseType.Fail);
            }

        }

        public ApiResponse AttendanceBatch(int allotId, int hospitalId, SaveCollectData request)
        {
            var dict = new Dictionary<string, string>();
            Vacation.ForEach(t => dict.Add(t.Item1, t.Item2));

            var dicData = CreateDataRow(request, dict);
            if (dicData == null || dicData.Count == 0)
                return new ApiResponse(ResponseType.Error, "空数据，无效操作");


            var convertDicData = dicData.Select(w => new RecordAttendcance
            {
                PersonnelNumber = w["PersonnelNumber"],
                PersonnelName = w["PersonnelName"],
                AttendanceName = w["AttendanceName"],
                BegDate = ConvertHelper.To<DateTime>(w["BegDate"]),
                EndDate = ConvertHelper.To<DateTime>(w["EndDate"]),
            });

            var jsons = JsonHelper.Serialize(convertDicData);
            var newAttendanceVacatione = JsonHelper.Deserialize<List<RecordAttendcance>>(jsons);
            var oldAttendanceVacatione = perfoPperAttendanceVacationeRepository.GetEntities(t => t.AllotId == allotId && t.HospitalId == hospitalId);

            var attendanceType = perfoPperAttendanceTypeRepository.GetEntities();
            var per_employee = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId && t.HospitalId == hospitalId);

            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();
            var per_allot = perforPerallotRepository.GetEntities(t => t.ID == allotId && t.HospitalId == hospitalId).FirstOrDefault();

            for (int i = 0; i < newAttendanceVacatione.Count; i++)
            {

                if (string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelName?.Trim())
                    || string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelNumber?.Trim())
                    || string.IsNullOrEmpty(newAttendanceVacatione[i].AttendanceName?.Trim())
                    || newAttendanceVacatione[i].BegDate == DateTime.MinValue
                    || newAttendanceVacatione[i].EndDate == DateTime.MinValue)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "“关键信息缺失”请补全或删除" },
                    });
                }

                var typeAny = attendanceType.FirstOrDefault(t => t.AllotId == allotId && t.HospitalId == hospitalId && t.AttendanceName == newAttendanceVacatione[i].AttendanceName);
                if (typeAny == null)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "没有该考勤类型" },
                    });
                }
                if (newAttendanceVacatione[i].PersonnelName != per_employee.FirstOrDefault(t => t.PersonnelNumber == newAttendanceVacatione[i].PersonnelNumber && t.AllotId == allotId && t.HospitalId == hospitalId)?.DoctorName)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "该人员与人员字典不一致或不存在" },
                    });
                }
                var oldEmp = oldAttendanceVacatione.FirstOrDefault(w => w.PersonnelNumber == newAttendanceVacatione[i].PersonnelNumber);
                if (!string.IsNullOrEmpty(newAttendanceVacatione[i].PersonnelName) && oldEmp != null && oldEmp.PersonnelName != newAttendanceVacatione[i].PersonnelName)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "“粘贴数据”与“历史数据”比对" },
                        { "错误原因", $"原名“{oldEmp.PersonnelName}”,工号相同但姓名不同,请删除“历史数据”中该员工" },
                    });

                }

                DateTime dt = new DateTime(per_allot.Year, per_allot.Month, 1);
                if (newAttendanceVacatione[i].BegDate >= dt && newAttendanceVacatione[i].EndDate > dt.AddMonths(1))
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "考勤时间不在该绩效月份内" },
                    });
                }
                if (newAttendanceVacatione[i].BegDate > newAttendanceVacatione[i].EndDate)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                        { "来源", "粘贴数据" },
                        { "错误原因", "开始时间不能大于结束时间" },
                    });
                }

                var newDate = SplitEveryDay(Convert.ToDateTime(newAttendanceVacatione[i].BegDate), Convert.ToDateTime(newAttendanceVacatione[i].EndDate));

                //foreach (var item in oldAttendanceVacatione.Where(w => w.PersonnelNumber == newAttendanceVacatione[i].PersonnelNumber))
                //{
                //    var oldDate = SplitEveryDay(Convert.ToDateTime(item.BegDate), Convert.ToDateTime(item.EndDate));

                //    bool any = false;
                //    foreach (var old in oldDate)
                //    {
                //        if (newDate.Contains(old))
                //            any = true;
                //    }
                //    if (any)
                //        error.Add(new Dictionary<string, string>
                //        {
                //        { "行号", $"第{i+1}行" },
                //        { "人员工号", newAttendanceVacatione[i].PersonnelNumber??"" },
                //        { "人员姓名", newAttendanceVacatione[i].PersonnelName??"" },
                //        { "考勤类型", newAttendanceVacatione[i].AttendanceName??"" },
                //        { "开始日期", newAttendanceVacatione[i].BegDate.ToString()??"" },
                //        { "结束日期", newAttendanceVacatione[i].EndDate.ToString()??"" },
                //        { "来源", "粘贴数据" },
                //        { "错误原因", "该考勤时间范围与历史考勤时间冲突" },
                //        });
                //}
            }
            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            List<per_attendance_vacation> addAttendanceVacatione = new List<per_attendance_vacation>();

            var type = GetAttendanceType(allotId);
            foreach (var data in newAttendanceVacatione)
            {
                data.AllotId = allotId;
                data.HospitalId = hospitalId;
                data.TypeId = type.Data.FirstOrDefault(t => t.AttendanceName == data.AttendanceName).Id;
                addAttendanceVacatione.Add(data);
                var any = oldAttendanceVacatione.FirstOrDefault(w => w.AllotId == allotId && w.HospitalId == hospitalId && w.BegDate == data.BegDate && w.EndDate == data.EndDate && w.PersonnelName?.Trim() == data.PersonnelName?.Trim() && w.PersonnelNumber?.Trim() == data.PersonnelNumber?.Trim() && w.TypeId == data.TypeId);
            }

            perfoPperAttendanceVacationeRepository.RemoveRange(oldAttendanceVacatione.ToArray());
            if (addAttendanceVacatione != null && addAttendanceVacatione.Any())
                perfoPperAttendanceVacationeRepository.AddRange(addAttendanceVacatione.ToArray());

            return new ApiResponse(ResponseType.OK, "");

        }
        #endregion

        public ApiResponse<List<AttendanceStatistics>> GetAttendanceStatistics(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(w => w.ID == allotId);
            if (allot == null)
                throw new PerformanceException("当前绩效记录不存在");

            var types = perfoPperAttendanceTypeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_attendance_type>();
            var vacationeData = perfoPperAttendanceVacationeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_attendance_vacation>();
            //// 只关注请假的人
            //var numbers = vacationeData.Select(w => w.PersonnelNumber).ToList();
            //var attendanceData = perforPerallotRepository.GetAttendance(allotId)
            //    .Where(w => numbers.Contains(w.PersonnelNumber))
            //    .ToList();
            var attendanceData = perforPerallotRepository.GetAttendance(allotId);

            List<AttendanceStatistics> statistics = new List<AttendanceStatistics>();
            // 交叉补全科室结束时间
            foreach (var personnelNumber in attendanceData.Select(w => w.PersonnelNumber).Distinct())
            {
                var attendances = attendanceData.Where(w => w.PersonnelNumber == personnelNumber).OrderBy(w => w.AttendanceDate);
                for (int i = 0; i < attendances.Count() - 1; i++)
                {
                    var begDate = attendances.ElementAt(i).AttendanceDate.Date;
                    var endDate = attendances.ElementAt(i + 1).AttendanceDate.Date;
                    // 调入科室需要额外减去1天作为上一个科室结束时间
                    var days = attendances.ElementAt(i + 1).Source == Attendance.Type.调入.ToString() ? -1 : 0;
                    if (endDate > begDate)
                    {
                        var stat = new AttendanceStatistics
                        {
                            AllotID = attendances.ElementAt(i).ALLOTID,
                            UnitType = attendances.ElementAt(i).UnitType,
                            AccountingUnit = attendances.ElementAt(i).AccountingUnit,
                            Department = attendances.ElementAt(i).Department,
                            PersonnelNumber = attendances.ElementAt(i).PersonnelNumber,
                            PersonnelName = attendances.ElementAt(i).PersonnelName,
                            BeginDate = begDate,
                            EndDate = endDate.AddDays(days),
                            Detial = new List<AttendanceStatisticsDetial>()
                        };
                        statistics.Add(stat);
                    }
                }
            }

            var vacationes = vacationeData
                .Where(w => w.BegDate > DateTime.MinValue && w.EndDate > DateTime.MinValue)
                .Select(w => new
                {
                    w.PersonnelNumber,
                    Type = types.FirstOrDefault(p => p.Id == w.TypeId)?.AttendanceName ?? "考勤类型缺失",
                    Dates = SplitEveryDay(w.BegDate.Date, w.EndDate.Date),
                    Remark = types.FirstOrDefault(p => p.Id == w.TypeId)?.IsDeduction == (int)Attendance.Deduction.核减 ? "核减" : "不核减",
                });


            foreach (var stat in statistics)
            {
                stat.Detial = vacationes
                    .Where(w => w.PersonnelNumber == stat.PersonnelNumber)
                    .Select(w => new AttendanceStatisticsDetial
                    {
                        Title = w.Type,
                        Value = w.Dates.Where(date => date >= stat.BeginDate && date <= stat.EndDate).Count(),
                        Remark = w.Remark,
                    })
                    .ToList();

                foreach (var item in types)
                {
                    if (!stat.Detial.Any(w => w.Title == item.AttendanceName))
                    {
                        stat.Detial.Add(new AttendanceStatisticsDetial
                        {
                            Title = item.AttendanceName,
                            Value = 0,
                            Remark = item.IsDeduction == (int)Attendance.Deduction.核减 ? "核减" : "不核减",
                        });
                    }
                }
                int vacationesDays = stat.Detial.Where(w => !w.Remark.Contains("不核减")).Sum(w => w.Value);
                stat.AttendanceDays = SplitEveryDay(stat.BeginDate, stat.EndDate).Where(date => date >= stat.BeginDate && date <= stat.EndDate).Count() - vacationesDays;
            }
            return new ApiResponse<List<AttendanceStatistics>>(ResponseType.OK, "", statistics);
        }

        // 拆分请假时间段为每个日期
        private List<DateTime> SplitEveryDay(DateTime begin, DateTime end)
        {
            List<DateTime> dates = new List<DateTime>();
            for (int i = 0; i <= (end - begin).TotalDays; i++)
            {
                dates.Add(begin.AddDays(i));
            }
            return dates;
        }


        private List<Dictionary<string, string>> CreateDataRow(SaveCollectData request, Dictionary<string, string> config)
        {
            List<Dictionary<string, string>> allData = new List<Dictionary<string, string>>();

            for (int r = 0; r < request.Data.Length; r++)
            {
                // 创建固定数据列
                Dictionary<string, string> baseData = CreateBaseData(request, config, r);
                allData.Add(baseData);

            }
            return allData;
        }

        private Dictionary<string, string> CreateBaseData(SaveCollectData request, Dictionary<string, string> config, int rownumber)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            for (int c = 0; c < request.ColHeaders.Length; c++)
            {
                var header = request.ColHeaders[c];
                var first = config.FirstOrDefault(w => w.Value == header);
                if (!default(KeyValuePair<string, string>).Equals(first)
                    && !result.ContainsKey(header)
                    && request.Data[rownumber].Length > c)
                {
                    result.Add(first.Key, request.Data[rownumber][c]);
                }
            }

            return result;
        }

        public string ExcelDownload(List<Dictionary<string, object>> rows, string name, int allotId, List<ExcelDownloadHeads> headList)
        {
            var perAllot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            string title = $"{ perAllot.Year}年{perAllot.Month}月{name}";

            var data = new List<Dictionary<string, object>>();
            foreach (var obj in rows)
            {
                Dictionary<string, object> nobj = new Dictionary<string, object>();

                foreach (var item in obj)
                {
                    var lower = item.Key.ToLower();

                    if (lower.Contains("date"))
                        nobj[lower] = Convert.ToDateTime(item.Value).ToString("d");
                    else if (lower.Contains("detial"))
                    {
                        var detRows = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(item.Value.ToString());
                        foreach (var detlist in detRows)
                        {
                            string value = "";
                            foreach (var detitem in detlist)
                            {
                                if (detitem.Key == "Value") value = detitem.Value.ToString();
                                if (detitem.Key == "Title") nobj[detitem.Value.ToString()] = value;
                            }

                        }
                    }
                    else
                        nobj[lower] = item.Value;
                }
                data.Add(nobj);
            }

            var dpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Files");
            if (!Directory.Exists(dpath)) Directory.CreateDirectory(dpath);

            string filepath = Path.Combine(dpath, $"{name}{DateTime.Now:yyyy年MM月dd日}");
            if (File.Exists(filepath)) File.Delete(filepath);

            using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate))
            using (ExcelPackage package = new ExcelPackage(fs))
            {
                var worksheet = package.Workbook.Worksheets.Add(name);

                if (rows != null && rows.Count() > 0)
                {
                    worksheet.SetValue(1, 1, title);

                    for (int col = 0; col < headList.Count; col++)
                    {
                        worksheet.SetValue(2, col + 1, headList[col].Alias);
                    }
                    for (int col = 0; col < headList.Count; col++)
                    {
                        for (int row = 0; row < data.Count(); row++)
                        {
                            var temp = data.ElementAt(row);
                            var low = temp.Keys.ToString().ToLower();
                            var value = temp[headList[col].Name.ToLower()];

                            worksheet.Cells[row + 3, col + 1].Value = value;
                        }
                    }

                    #region 样式设置
                    for (int row = worksheet.Dimension.Start.Row; row <= worksheet.Dimension.End.Row; row++)
                    {
                        worksheet.Row(row).Height = 20;
                        for (int col = worksheet.Dimension.Start.Column; col <= worksheet.Dimension.End.Column; col++)
                        {
                            worksheet.Cells[row, col].Style.Border.BorderAround(ExcelBorderStyle.Thin);
                            worksheet.Cells[row, col].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                            worksheet.Cells[row, col].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                        }
                    }
                    worksheet.Cells[1, 1, 1, headList.Count].Merge = true;
                    worksheet.Cells[1, 1, 1, headList.Count].Style.Font.Bold = true;
                    worksheet.Cells[1, 1, 1, headList.Count].Style.Font.Size = 16;
                    worksheet.Row(1).Height = 24;
                    worksheet.Cells[2, 1, 2, headList.Count].Style.Font.Bold = true;
                    worksheet.View.FreezePanes(3, 1);
                    worksheet.Cells.AutoFitColumns();
                    for (int col = worksheet.Dimension.Start.Column; col <= worksheet.Dimension.End.Column; col++)
                    {
                        worksheet.Column(col).Width = worksheet.Column(col).Width > 20 ? 20 : worksheet.Column(col).Width;
                    }
                    #endregion
                }
                package.Save();
            }
            return filepath;
        }

        public static List<(string, string, Func<per_attendance, object>)> Person { get; } = new List<(string, string, Func<per_attendance, object>)>
        {
            (nameof(per_attendance.PersonnelName), "人员姓名", t => t.PersonnelName),
            (nameof(per_attendance.PersonnelNumber), "员工工号", t => t.PersonnelNumber),
            (nameof(per_attendance.CallInAccountingUnit), "调入核算单元" ,t => t.CallInAccountingUnit),
            (nameof(per_attendance.CallInUnitType), "调入组别", t => t.CallInUnitType),
            (nameof(per_attendance.CallInDate), "调入时间", t => t.CallInDate),
        };
        public static List<(string, string, Func<view_attendance, object>)> Person2 { get; } = new List<(string, string, Func<view_attendance, object>)>
        {
            (nameof(view_attendance.PersonnelName), "人员姓名", t => t.PersonnelName),
            (nameof(view_attendance.PersonnelNumber), "员工工号", t => t.PersonnelNumber),
            (nameof(view_attendance.AccountingUnit), "调入核算单元" ,t => t.AccountingUnit),
            (nameof(view_attendance.UnitType), "调入组别", t => t.UnitType),
            (nameof(view_attendance.AttendanceDate), "调入时间", t => t.AttendanceDate),
        };

        public static List<(string, string, Func<RecordAttendcance, object>)> Vacation { get; } = new List<(string, string, Func<RecordAttendcance, object>)>
        {
            (nameof(RecordAttendcance.PersonnelName), "人员姓名", t => t.PersonnelName),
            (nameof(RecordAttendcance.PersonnelNumber), "员工工号", t => t.PersonnelNumber),
            (nameof(RecordAttendcance.AttendanceName), "考勤类型" ,t => t.AttendanceName),
            (nameof(RecordAttendcance.BegDate), "开始时间", t => t.BegDate),
            (nameof(RecordAttendcance.EndDate), "结束时间", t => t.EndDate),
        };
    }
}
