using AutoMapper;
using Microsoft.Extensions.Logging;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Performance.Services
{
    public class HistoryService : IAutoInjection
    {
        private readonly IMapper _mapper;
        private readonly ILogger<EmployeeService> logger;
        private readonly PerforReportoriginalsurgeryRepository reportoriginalsurgeryRepository;
        private readonly PerforReportoriginalstaysRepository reportoriginalstaysRepository;
        private readonly PerforReportoriginalpersontimeRepository reportoriginalpersontimeRepository;
        private readonly PerforPerdeptdicRepository perdeptdicRepository;

        public HistoryService(
            IMapper mapper,
            ILogger<EmployeeService> logger,
            PerforReportoriginalsurgeryRepository reportoriginalsurgeryRepository,
            PerforReportoriginalstaysRepository reportoriginalstaysRepository,
            PerforReportoriginalpersontimeRepository reportoriginalpersontimeRepository,
            PerforPerdeptdicRepository perdeptdicRepository)
        {
            _mapper = mapper;
            this.logger = logger;
            this.reportoriginalsurgeryRepository = reportoriginalsurgeryRepository;
            this.reportoriginalstaysRepository = reportoriginalstaysRepository;
            this.reportoriginalpersontimeRepository = reportoriginalpersontimeRepository;
            this.perdeptdicRepository = perdeptdicRepository;
        }
        public void ImportHistoryData(int hospitalid, string path)
        {
            try
            {
                var entities = ReadExcelData(hospitalid, path);

                var @data1 = entities.Where(w => w.SheetName == "工作量");
                if (@data1.Any())
                {
                    var years = @data1.Select(s => s.Year).Distinct().ToList();
                    var months = @data1.Select(s => s.Month).Distinct().ToList();
                    reportoriginalpersontimeRepository.RemoveRange(w => w.HospitalID == hospitalid && years.Contains(w.Year) && months.Contains(w.Month));

                    var @data = _mapper.Map<List<report_original_persontime>>(@data1);
                    reportoriginalpersontimeRepository.AddRange(@data.ToArray());
                }
                var @data2 = entities.Where(w => w.SheetName == "手术量");
                if (@data2.Any())
                {
                    var years = @data2.Select(s => s.Year).Distinct().ToList();
                    var months = @data2.Select(s => s.Month).Distinct().ToList();
                    reportoriginalsurgeryRepository.RemoveRange(w => w.HospitalID == hospitalid && years.Contains(w.Year) && months.Contains(w.Month));

                    var @data = _mapper.Map<List<report_original_surgery>>(@data2);
                    reportoriginalsurgeryRepository.AddRange(@data.ToArray());
                }
                var @data3 = entities.Where(w => w.SheetName == "住院天数");
                if (@data3.Any())
                {
                    var years = @data3.Select(s => s.Year).Distinct().ToList();
                    var months = @data3.Select(s => s.Month).Distinct().ToList();
                    reportoriginalstaysRepository.RemoveRange(w => w.HospitalID == hospitalid && years.Contains(w.Year) && months.Contains(w.Month));

                    var @data = _mapper.Map<List<report_original_stays>>(@data3);
                    reportoriginalstaysRepository.AddRange(@data.ToArray());
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());
            }
        }

        private List<HistoryData> ReadExcelData(int hospitalid, string path)
        {
            var entities = new List<HistoryData>();
            var config = new[]
            {
                new { sheetName = "工作量", columnNames = new string[] { "年份", "月份", "来源", "科室", "数量" } },
                new { sheetName = "手术量", columnNames = new string[] { "年份", "月份", "来源", "科室", "数量" } },
                new { sheetName = "住院天数", columnNames = new string[] { "年份", "月份", "来源", "科室", "数量" } },
            };

            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 entities;
            foreach (var cfg in config)
            {
                var sheet = workbook.GetSheet(cfg.sheetName);
                if (sheet == null) continue;

                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>();
                cfg.columnNames.ToList().ForEach(w => dict.Add(w, -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)}");

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

                    var entity = new HistoryData
                    {
                        SheetName = cfg.sheetName,
                        HospitalID = hospitalid,
                        Year = ConvertHelper.To<int>(row.GetCell(dict["年份"]).GetValue()),
                        Month = ConvertHelper.To<int>(row.GetCell(dict["月份"]).GetValue()),
                        SourceType = row.GetCell(dict["来源"]).GetValue(),
                        Department = row.GetCell(dict["科室"]).GetValue(),
                        ResultData = ConvertHelper.To<decimal>(row.GetCell(dict["数量"]).GetValue()),
                    };
                    //if (dict.ContainsKey("核算单元"))
                    //    entity.AccountingUnit = row.GetCell(dict["核算单元"]).GetValue();
                    entities.Add(entity);
                }
            }

            var departmentDict = perdeptdicRepository.GetEntities(t => t.HospitalId == hospitalid);
            if (departmentDict != null && departmentDict.Any())
            {
                var unittype = UnitTypeUtil.GetUnitTypeFromEnum();
                entities.ForEach(t =>
                {
                    var accountingUnits = departmentDict.Where(w => w.Department == t.Department && w.Source == t.SourceType);
                    if (accountingUnits != null && accountingUnits.Any())
                    {
                        var accountingUnit = accountingUnits.OrderBy(o => (unittype.FirstOrDefault(f => f.Name == o.UnitType)?.Value) ?? int.MaxValue).FirstOrDefault(f => !string.IsNullOrEmpty(f.AccountingUnit))?.AccountingUnit;
                        t.AccountingUnit = accountingUnit;
                    }
                });
            }
            return entities;
        }
    }
}
