using AutoMapper;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Performance.Services
{
    public class AgainAllotService : IAutoInjection
    {
        private Application application;
        private AgainService againService;
        private RoleService roleService;
        private ConfigService configService;
        private PerforCofagainRepository perforCofagainRepository;
        private PerforPeragainallotRepository perforPeragainallotRepository;
        private PerforResaccountRepository perforResaccountRepository;
        //private PerforResaccountnurseRepository perforResaccountnurseRepository;
        private PerforUserRepository perforUserRepository;
        private PerforUserhospitalRepository perforUserhospitalRepository;
        private PerforPerallotRepository perforPerallotRepository;

        private PerforAgagainsituationRepository perforAgagainsituationRepository;
        private PerforAgdataRepository perforAgdataRepository;
        private PerforAgemployeeRepository perforAgemployeeRepository;
        private PerforAgheaderRepository perforAgheaderRepository;

        public AgainAllotService(IOptions<Application> options, AgainService againService,
            RoleService roleService,
            PerforCofagainRepository perforCofagainRepository,
            PerforPeragainallotRepository perforPeragainallotRepository,
            PerforResaccountRepository perforResaccountRepository,
            //PerforResaccountnurseRepository perforResaccountnurseRepository,
            PerforUserRepository perforUserRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforAgagainsituationRepository perforAgagainsituationRepository,
            PerforAgdataRepository perforAgdataRepository,
            PerforAgemployeeRepository perforAgemployeeRepository,
            PerforAgheaderRepository perforAgheaderRepository,
            ConfigService configService)
        {
            this.application = options.Value;
            this.againService = againService;
            this.roleService = roleService;
            this.perforCofagainRepository = perforCofagainRepository;
            this.perforPeragainallotRepository = perforPeragainallotRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            //this.perforResaccountnurseRepository = perforResaccountnurseRepository;
            this.perforUserRepository = perforUserRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perforPerallotRepository = perforPerallotRepository;

            this.perforAgagainsituationRepository = perforAgagainsituationRepository;
            this.perforAgdataRepository = perforAgdataRepository;
            this.perforAgemployeeRepository = perforAgemployeeRepository;
            this.perforAgheaderRepository = perforAgheaderRepository;

            this.configService = configService;
        }

        ///// <summary>
        ///// 生成二次绩效
        ///// </summary>
        ///// <param name="request"></param>
        //public bool Generate(AgainAllotRequest request, int userId, string department)
        //{
        //    var againAllot = perforPeragainallotRepository.GetEntity(t => t.ID == request.AgainAllotID);
        //    if (againAllot == null || againAllot.ID == 0)
        //        throw new PerformanceException("绩效二次分配不存在");

        //    var roles = roleService.GetRole(userId);

        //    perforPeragainallotRepository.Update(againAllot, p => { p.States = 2; });

        //    //清理二次绩效无用数据
        //    configService.ClearAgain(againAllot.ID);
        //    try
        //    {
        //        #region 基础信息
        //        //获取基础配置信息
        //        var config = perforCofagainRepository.GetEntities(t => t.AllotID == againAllot.AllotID);
        //        var jobfactor = config.FirstOrDefault(t => t.Type == 1)?.Value;
        //        var workfactor = config.FirstOrDefault(t => t.Type == 2)?.Value;
        //        var days = config.FirstOrDefault(t => t.Type == 3)?.Value;

        //        decimal? basicnumber = 0m;
        //        //获取科室实发绩效
        //        if (roles != null)
        //        {
        //            var role = roles.FirstOrDefault();
        //            if (role != null)
        //            {
        //                if (application.NurseRole == role.Type)
        //                    basicnumber = perforResaccountRepository.GetEntity(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == againAllot.AllotID && t.AccountingUnit == department)?.RealGiveFee;
        //                else if (application.DirectorRole == role.Type)
        //                    basicnumber = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == againAllot.AllotID && t.AccountingUnit == department)?.RealGiveFee;
        //            }
        //        }
        //        #endregion

        //        #region 计算
        //        //读取二次计算excel数据
        //        var perAgainExcel = againService.ReadData(againAllot);
        //        //护士长或科主任出勤
        //        var bossAttendance = perAgainExcel.AgainEmployee.FirstOrDefault(t => t.JobTitle == "护士长")?.Attendance;
        //        //计算职称出勤系数、年资出勤系数
        //        foreach (var item in perAgainExcel.AgainEmployee)
        //        {
        //            item.JobAttendanceFactor = item.JobFactor * item.Attendance / days;
        //            item.YearAttendanceFactor = item.Attendance * item.YearFactor / days;
        //        }
        //        //计算 科室系数人均
        //        var departmentFactorAvg = basicnumber / perAgainExcel.AgainEmployee.Sum(t => t.YearAttendanceFactor);
        //        //二次分配科室概览
        //        PerAgainSituation situation = new PerAgainSituation
        //        {
        //            NightShift = perAgainExcel.AgainEmployee.Sum(t => t.NightShift),
        //            DepartmentTotal = basicnumber,
        //            BossPerfor = departmentFactorAvg * bossAttendance / days,
        //            Award = perAgainExcel.AgainEmployee.Sum(t => t.Award),
        //            Allowance = perAgainExcel.AgainEmployee.Sum(t => t.Allowance),
        //            AlonePerfor = perAgainExcel.AgainEmployee.Sum(t => t.AlonePerfor),
        //            Attendance = days,
        //            DepartmentFactorAvg = departmentFactorAvg
        //        };
        //        //业绩二次分配科室概览：业绩分配绩效、职称绩效、工作量绩效
        //        situation.AllotPerfor = situation.DepartmentTotal - situation.BossPerfor - situation.Award - situation.Allowance - situation.AlonePerfor;
        //        situation.JobPerfor = situation.AllotPerfor * jobfactor;
        //        situation.WorkloadPerfor = situation.AllotPerfor * workfactor;

        //        var rowList = perAgainExcel.AgainData.Select(t => t.RowNumber).Distinct().ToList();
        //        //业绩二次分配科室动态数据：工作量得分
        //        foreach (var rowNumber in rowList)
        //        {
        //            var againEmployee = perAgainExcel.AgainEmployee.FirstOrDefault(t => t.RowNumber == rowNumber);
        //            var atRowList = perAgainExcel.AgainData.Where(t => t.RowNumber == rowNumber);
        //            decimal? sumValue = 0m;
        //            foreach (var atRow in atRowList)
        //                sumValue += atRow.IsFactor == 1 ? atRow.IsFactor * atRow.CellValue : atRow.CellValue;
        //            sumValue = sumValue * againEmployee?.YearFactor;

        //            var head = perAgainExcel.Header.Children.FirstOrDefault(t => t.CellValue == "工作量得分");
        //            if (head == null)
        //            {
        //                perAgainExcel.Header.MergeCell++;
        //                var pointrow = perAgainExcel.Header.Children.Max(t => t.PointRow);
        //                var pointcell = perAgainExcel.Header.Children.Max(t => t.PointCell);
        //                head = new PerHeader(pointrow, pointcell, "工作量得分", 1, 1, 1, null, 1);
        //                perAgainExcel.Header.Children.Add(head);
        //            }
        //            perAgainExcel.AgainData.Add(new PerAgainData(rowNumber.Value, "工作量得分", sumValue, 1, 2, null, "", "", head.SignID));
        //        }
        //        //业绩二次分配科室动态数据：绩效工资
        //        foreach (var rowNumber in rowList)
        //        {
        //            var workvalue = perAgainExcel.AgainData.FirstOrDefault(t => t.RowNumber == rowNumber && t.TypeName == "工作量得分")?.CellValue;
        //            var sumvalue = perAgainExcel.AgainData.Where(t => t.TypeName == "工作量得分").Sum(t => t.CellValue);

        //            var perforValue = workvalue / sumvalue * situation.WorkloadPerfor;

        //            var head = perAgainExcel.Header.Children.FirstOrDefault(t => t.CellValue == "绩效工资");
        //            if (head == null)
        //            {
        //                perAgainExcel.Header.MergeCell++;
        //                var pointrow = perAgainExcel.Header.Children.Max(t => t.PointRow);
        //                var pointcell = perAgainExcel.Header.Children.Max(t => t.PointCell);
        //                head = new PerHeader(pointrow, pointcell, "绩效工资", 1, 1, 1, null, 1);
        //                perAgainExcel.Header.Children.Add(head);
        //            }
        //            perAgainExcel.AgainData.Add(new PerAgainData(rowNumber.Value, "绩效工资", perforValue, 1, 2, null, "", "", head.SignID));
        //        }

        //        //业绩二次分配科室：应发绩效、实发绩效
        //        string[] jobArray = new string[] { "护士长", "科主任" };
        //        foreach (var employee in perAgainExcel.AgainEmployee)
        //        {
        //            if (jobArray.Contains(employee.JobTitle))
        //            {
        //                employee.GiveFee = situation.BossPerfor;
        //                employee.RealGiveFee = situation.BossPerfor;
        //            }
        //            else
        //            {
        //                employee.JobAttendancePerfor = situation.JobPerfor * employee.JobAttendanceFactor / perAgainExcel.AgainEmployee.Sum(t => t.JobAttendanceFactor);
        //                var value = perAgainExcel.AgainData.FirstOrDefault(t => t.RowNumber == employee.RowNumber && t.TypeName == "绩效工资")?.CellValue;
        //                employee.GiveFee = (employee.JobAttendancePerfor ?? 0) + (value ?? 0) + (employee.Award ?? 0) + (employee.Allowance ?? 0) + (employee.AlonePerfor ?? 0);
        //                employee.RealGiveFee = (employee.GiveFee ?? 0) + (employee.NightShift ?? 0);
        //            }
        //        }
        //        #endregion

        //        #region 保存

        //        var againsituation = Mapper.Map<ag_againsituation>(situation);
        //        againsituation.AllotID = againAllot.AllotID;
        //        againsituation.AgainAllotID = againAllot.ID;
        //        perforAgagainsituationRepository.Add(againsituation);

        //        var employeeList = Mapper.Map<List<ag_employee>>(perAgainExcel.AgainEmployee);
        //        employeeList.ForEach(item => { item.AllotID = againAllot.AllotID; item.AgainAllotID = againAllot.ID; });
        //        perforAgemployeeRepository.AddRange(employeeList.ToArray());

        //        var pHeader = Mapper.Map<ag_header>(perAgainExcel.Header);
        //        pHeader.AllotID = againAllot.AllotID;
        //        pHeader.AgainAllotID = againAllot.ID;
        //        var cHeaderList = Mapper.Map<List<ag_header>>(perAgainExcel.Header.Children);
        //        cHeaderList.ForEach(item => { item.AllotID = againAllot.AllotID; item.AgainAllotID = againAllot.ID; });
        //        perforAgheaderRepository.Add(pHeader);
        //        perforAgheaderRepository.AddRange(cHeaderList.ToArray());

        //        var dataList = Mapper.Map<List<ag_data>>(perAgainExcel.AgainData);
        //        dataList.ForEach(item => { item.AllotID = againAllot.AllotID; item.AgainAllotID = againAllot.ID; });
        //        perforAgdataRepository.AddRange(dataList.ToArray());

        //        #endregion
        //    }
        //    catch (Exception ex)
        //    {
        //        perforPeragainallotRepository.Update(againAllot, p => { p.States = 4; p.Remark = ex.ToString(); });
        //    }
        //    perforPeragainallotRepository.Update(againAllot, p => { p.States = 3; });
        //    return true;
        //    //return SheetFormat(perAgainExcel, situation);
        //}

        /// <summary>
        /// 绩效详情表格转换
        /// </summary>
        /// <param name="perAgainExcel"></param>
        /// <param name="situation"></param>
        /// <returns></returns>
        private (SheetExportResponse SheetExport, PerAgainSituation AgainSituation) SheetFormat(PerAgainExcel perAgainExcel, PerAgainSituation situation)
        {
            #region 表格显示
            SheetExportResponse response = new SheetExportResponse("二次绩效分配表");
            //返回表格展示数据结构
            var row = new Row(0);
            row.Data.Add(new Cell(1, "姓名", 2, 1, false, false));
            row.Data.Add(new Cell(2, "职务", 2, 1, false, false));
            row.Data.Add(new Cell(3, "职称系数", 2, 1, false, false));
            row.Data.Add(new Cell(4, "出勤", 2, 1, false, false));
            row.Data.Add(new Cell(5, "职称出勤系数", 2, 1, false, false));
            row.Data.Add(new Cell(6, "年资", 2, 1, false, false));
            row.Data.Add(new Cell(7, "年资出勤系数", 2, 1, false, false));
            row.Data.Add(new Cell(8, "职称出勤绩效", 2, 1, false, false));
            row.Data.Add(new Cell(9, perAgainExcel.Header.CellValue, 1, perAgainExcel.Header.Children.Count, false, false));
            row.Data.Add(new Cell(9 + perAgainExcel.Header.Children.Count, "重点奖励", 2, 1, false, false));
            row.Data.Add(new Cell(10 + perAgainExcel.Header.Children.Count, "管理津贴", 2, 1, false, false));
            row.Data.Add(new Cell(11 + perAgainExcel.Header.Children.Count, "单独核算人员绩效", 2, 1, false, false));
            row.Data.Add(new Cell(12 + perAgainExcel.Header.Children.Count, "应发绩效工资金额", 2, 1, false, false));
            row.Data.Add(new Cell(13 + perAgainExcel.Header.Children.Count, "夜班费", 2, 1, false, false));
            row.Data.Add(new Cell(14 + perAgainExcel.Header.Children.Count, "实发工资合计", 2, 1, false, false));

            var rowTwo = new Row(1);
            int startpoint = 9;
            perAgainExcel.Header.Children.ForEach(t =>
            {
                rowTwo.Data.Add(new Cell(startpoint, t.CellValue, 1, 1, false, false));
                startpoint++;
            });
            response.Header.Add(row);
            response.Header.Add(rowTwo);

            for (int i = 0; i < perAgainExcel.AgainEmployee.Count(); i++)
            {
                var item = perAgainExcel.AgainEmployee.ElementAt(i);
                var rowbody = new Row(i);
                rowbody.Data.Add(new Cell(1, item.Name, 1, 1, false, false));
                rowbody.Data.Add(new Cell(2, item.JobTitle, 1, 1, false, false));
                rowbody.Data.Add(new Cell(3, item.JobFactor, 1, 1, false, false));
                rowbody.Data.Add(new Cell(4, item.Attendance, 1, 1, false, false));
                rowbody.Data.Add(new Cell(5, item.JobAttendanceFactor, 1, 1, false, false));
                rowbody.Data.Add(new Cell(6, item.YearFactor, 1, 1, false, false));
                rowbody.Data.Add(new Cell(7, item.YearAttendanceFactor, 1, 1, false, false));
                rowbody.Data.Add(new Cell(8, item.JobAttendancePerfor, 1, 1, false, false));

                var againList = perAgainExcel.AgainData.Where(t => t.RowNumber == item.RowNumber);
                startpoint = 9;
                perAgainExcel.Header.Children.ForEach(t =>
                {
                    var cellValue = againList.FirstOrDefault(s => t.SignID == s.SignID)?.CellValue;
                    rowbody.Data.Add(new Cell(startpoint, cellValue, 1, 1, false, false));
                    startpoint++;
                });
                rowbody.Data.Add(new Cell(9 + perAgainExcel.Header.Children.Count, item.Award, 1, 1, false, false));
                rowbody.Data.Add(new Cell(10 + perAgainExcel.Header.Children.Count, item.Allowance, 1, 1, false, false));
                rowbody.Data.Add(new Cell(11 + perAgainExcel.Header.Children.Count, item.AlonePerfor, 1, 1, false, false));
                rowbody.Data.Add(new Cell(12 + perAgainExcel.Header.Children.Count, item.GiveFee, 1, 1, false, false));
                rowbody.Data.Add(new Cell(13 + perAgainExcel.Header.Children.Count, item.NightShift, 1, 1, false, false));
                rowbody.Data.Add(new Cell(14 + perAgainExcel.Header.Children.Count, item.RealGiveFee, 1, 1, false, false));
                response.Row.Add(rowbody);
            }
            #endregion

            return (response, situation);
        }

        /// <summary>
        /// 查看二次分配详情及概览
        /// </summary>
        /// <param name="request"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public (SheetExportResponse SheetExport, PerAgainSituation AgainSituation) Detail(AgainAllotRequest request)
        {
            var againAllot = perforPeragainallotRepository.GetEntity(t => t.ID == request.AgainAllotID);
            if (againAllot == null || againAllot.ID == 0)
                throw new PerformanceException("绩效二次分配不存在");

            var situation = perforAgagainsituationRepository.GetEntity(t => t.AgainAllotID == againAllot.ID);
            var againsituation = Mapper.Map<PerAgainSituation>(situation);

            var againEmployee = perforAgemployeeRepository.GetEntities(t => t.AgainAllotID == againAllot.ID);
            //var employeeList = Mapper.Map<List<PerAgainEmployee>>(againEmployee);

            var header = perforAgheaderRepository.GetEntities(t => t.AgainAllotID == againAllot.ID);
            //var headerList = Mapper.Map<List<PerHeader>>(header);

            var data = perforAgdataRepository.GetEntities(t => t.AgainAllotID == againAllot.ID);
            //var dataList = Mapper.Map<List<PerAgainData>>(data);

            var pHead = header.FirstOrDefault(t => t.CellValue == "工作量绩效工资");
            var head = Mapper.Map<PerHeader>(pHead);
            var cHead = Mapper.Map<List<PerHeader>>(header.Where(t => t.CellValue != "工作量绩效工资"));
            head.Children = cHead;

            var perAgainExcel = new PerAgainExcel
            {
                Header = head,
                AgainData = Mapper.Map<List<PerAgainData>>(data),
                AgainEmployee = Mapper.Map<List<PerAgainEmployee>>(againEmployee)
            };

            return SheetFormat(perAgainExcel, againsituation);
        }


        /// <summary>
        /// 二次绩效新增记录
        /// </summary>
        /// <param name="allot"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        public bool Update(per_allot allot, int againid)
        {
            var again = perforPeragainallotRepository.GetEntity(t => t.ID == againid);
            again.ID = againid;
            again.UploadDateTime = DateTime.Now;
            again.Path = allot.Path;
            again.Remark = allot.Remark;
            again.States = 1;
            return perforPeragainallotRepository.Update(again);
        }

        /// <summary>
        /// 根据人物角色获取绩效列表
        /// </summary>
        /// <returns></returns>
        public List<AgainAllotResponse> GetAllotList(int userid)
        {
            var user = perforUserRepository.GetEntity(t => t.ID == userid);
            if (user == null)
                throw new NotImplementedException("人员ID无效");
            var hospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userid);
            if (hospital == null)
                throw new NotImplementedException("人员未选择医院");
            var allot = perforPerallotRepository.GetEntities(t => t.HospitalId == hospital.HospitalID && t.States == 6);
            if (allot == null)
                throw new NotImplementedException("该医院未生成绩效");

            var allotId = allot.Select(t => t.ID).ToList();
            var again = perforPeragainallotRepository.GetEntities(t => allotId.Contains(t.AllotID.Value) && t.Department == user.Department);
            var arrId = again == null ? new List<int>() : again.Select(t => t.AllotID.Value).ToList();
            //取得未生成二次绩效的绩效id  
            var exceptId = allotId.Except(arrId).ToList();
            if (exceptId.Count > 0)
            {
                allot = allot.Where(t => exceptId.Contains(t.ID)).ToList();
                var model = allot.Select(t => new per_againallot
                {
                    AllotID = t.ID,
                    CreateUser = userid,
                    CreateDateTime = DateTime.Now,
                    Department = user.Department,
                    States = 0
                });
                //生成二次绩效
                perforPeragainallotRepository.AddRange(model.ToArray());
            }

            again = perforPeragainallotRepository.GetEntities(t => allotId.Contains(t.AllotID.Value) && t.CreateUser == userid);
            List<AgainAllotResponse> list = Mapper.Map<List<AgainAllotResponse>>(again);
            list.ForEach(t =>
            {
                var data = allot.Where(p => p.ID == t.AllotID).FirstOrDefault();
                t.Year = data.Year;
                t.Month = data.Month;
            });
            return list.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).ToList();
        }

        /// <summary>
        /// 获取状态不是归档的二次绩效的记录
        /// </summary>
        /// <param name="againid"></param>
        /// <returns></returns>
        public per_againallot GetAgainallot(int againid)
        {
            var list = perforPeragainallotRepository.GetEntity(t => t.ID == againid && t.States != 5);
            return list;
        }
    }
}
