using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Services.AllotCompute;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Performance.Services
{
    public class EmployeeService : IAutoInjection
    {
        private PerforImemployeeRepository perforImemployeeRepository;
        private PerforPersheetRepository perforPersheetRepository;
        private PerforPerallotRepository perforPerallotRepository;
        private PerforImemployeeclinicRepository perforImemployeeclinicRepository;
        private PerforUserhospitalRepository perforUserhospitalRepository;
        private PerforPerallotRepository perallotRepository;
        private PerforPerapramountRepository perapramountRepository;
        private PerforImemployeelogisticsRepository perforImemployeelogisticsRepository;
        private ILogger<EmployeeService> logger;

        public EmployeeService(PerforImemployeeRepository perforImemployeeRepository,
            PerforPersheetRepository perforPersheetRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perallotRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforImemployeelogisticsRepository perforImemployeelogisticsRepository,
            ILogger<EmployeeService> logger)
        {
            this.perforImemployeeRepository = perforImemployeeRepository;
            this.perforPersheetRepository = perforPersheetRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perallotRepository = perallotRepository;
            this.perapramountRepository = perapramountRepository;
            this.perforImemployeelogisticsRepository = perforImemployeelogisticsRepository;
            this.logger = logger;
        }

        #region 行政人员

        /// <summary>
        ///获取人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee GetEmployee(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            return employee;
        }

        /// <summary>
        ///获取人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee> GetEmployeeList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Insert(EmployeeRequest request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.Employee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "行政人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            var employee = Mapper.Map<im_employee>(request);
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.SheetID = sheet.ID;
            perforImemployeeRepository.Add(employee);
            return employee;
        }

        /// <summary>
        /// 修改人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Update(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool Delete(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeRepository.Remove(employee);
        }

        #endregion

        #region 临床人员

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_clinic> GetEmployeeClinicList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic InsertClinic(im_employee_clinic request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.ClinicEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeeclinicRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic UpdateClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.UnitType = request.UnitType;
            employee.Department = request.Department;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Efficiency = request.Efficiency;
            employee.Scale = request.Scale;
            employee.Management = request.Management;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeclinicRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeclinicRepository.Remove(employee);
        }

        #endregion       

        #region 行政后勤

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_logistics> GetEmployeeLogisticsList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.Archive, (int)AllotStates.GenerateSucceed }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeelogisticsRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics InsertLogistics(im_employee_logistics request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.LogisticsEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeelogisticsRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics UpdateLogistics(im_employee_logistics request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            //employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            //employee.PeopleNumber = request.PeopleNumber;
            //employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            //employee.Punishment = request.Punishment;
            //employee.Adjust = request.Adjust;
            //employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeelogisticsRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteLogistics(im_employee_clinic request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeelogisticsRepository.Remove(employee);
        }

        #endregion       

        /// <summary>
        /// 人事科修改后提交状态
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public bool Audit(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null || !new List<int> { (int)AllotStates.GenerateSucceed, (int)AllotStates.GenerateAccomplish }.Contains(allot.States))
                throw new PerformanceException("绩效信息错误");
            if ((int)AllotStates.Archive == allot.States)
                throw new PerformanceException("绩效已归档，暂不支持修改");

            allot.Generate = (int)AllotGenerate.PersonnelOffice;
            return perforPerallotRepository.Update(allot);
        }

        public List<per_apr_amount> GetAprList(int allotId)
        {
            var list = perapramountRepository.GetEntities(t => t.AllotId == allotId);
            if (list != null && list.Any())
                list = list.OrderBy(t => t.DoctorName).ToList();

            return list;
        }

        public bool InsertApr(per_apr_amount request, int userId)
        {
            if (request == null)
                return false;

            var data = perapramountRepository.GetEntity(t => t.PersonnelNumber == request.PersonnelNumber && t.AllotId == request.AllotId);
            if (data != null)
                throw new PerformanceException("人员工号已存在");

            request.CreateDate = DateTime.Now;
            request.CreateUser = userId;
            return perapramountRepository.Add(request);
        }

        public bool UpdateApr(per_apr_amount request)
        {
            if (request == null)
                return false;

            var data = perapramountRepository.GetEntity(t => t.Id == request.Id);
            if (data == null)
                throw new PerformanceException("修改数据无效");

            data.PersonnelNumber = request.PersonnelNumber;
            data.DoctorName = request.DoctorName;
            data.PerforType = request.PerforType;
            data.Amount = request.Amount;

            return perapramountRepository.Update(data);
        }

        public bool DeleteApr(int id)
        {
            var data = perapramountRepository.GetEntity(t => t.Id == id);
            if (data != null)
                return perapramountRepository.Remove(data);

            return true;
        }

        public void ImpoerAprEmployees(int allotid, string path, int userid)
        {
            var data = perapramountRepository.GetEntities(t => t.AllotId == allotid);
            if (data != null && data.Any())
                perapramountRepository.RemoveRange(data.ToArray());

            try
            {
                IWorkbook workbook = null;

                var version = FileHelper.GetExtension(path) == ".xlsx" ? ExcelVersion.xlsx : ExcelVersion.xls;
                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
                {
                    workbook = (version == ExcelVersion.xlsx)
                        ? (IWorkbook)(new XSSFWorkbook(fs))
                        : (IWorkbook)(new HSSFWorkbook(fs));
                }
                if (workbook == null) return;
                var sheet = workbook.GetSheetAt(0);

                var firstRow = sheet.GetRow(0);
                List<(string, int)> excelheader = new List<(string, int)>();
                for (int cellindex = 0; cellindex < firstRow.LastCellNum + 1; cellindex++)
                {
                    var cell = firstRow.GetCell(cellindex);
                    if (cell == null) continue;

                    if (!string.IsNullOrEmpty(cell.ToString()))
                        excelheader.Add((cell.ToString(), cellindex));
                }

                if (excelheader == null || !excelheader.Any())
                    throw new PerformanceException("上传excel内容错误");

                Dictionary<string, int> dict = new Dictionary<string, int>
                {
                    { "人员工号", -1 }, { "姓名", -1 }, { "绩效类型", -1 }, { "金额", -1 },
                };

                List<string> errorHeaders = new List<string>();
                foreach (var key in dict.Keys.ToList())
                {

                    if (!excelheader.Select(t => t.Item1).Contains(key)) errorHeaders.Add(key);
                    else dict[key] = excelheader.First(t => t.Item1 == key).Item2;
                }

                if (errorHeaders != null && errorHeaders.Any())
                    throw new PerformanceException($"excel缺少列{string.Join(", ", errorHeaders)}");

                var entities = new List<per_apr_amount>();
                var createtime = DateTime.Now;

                for (int rowindex = 1; rowindex < sheet.LastRowNum + 1; rowindex++)
                {
                    var row = sheet.GetRow(rowindex);
                    if (row == null) continue;

                    var entity = new per_apr_amount
                    {
                        PersonnelNumber = row.GetCell(dict["人员工号"])?.ToString(),
                        DoctorName = row.GetCell(dict["姓名"])?.ToString(),
                        PerforType = row.GetCell(dict["绩效类型"])?.ToString(),
                        Amount = (decimal)(row.GetCell(dict["金额"])?.NumericCellValue ?? 0),
                        AllotId = allotid,
                        CreateDate = createtime,
                        CreateUser = userid,
                    };
                    entities.Add(entity);
                }
                perapramountRepository.AddRange(entities.ToArray());
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());
            }
        }
    }
}
