using Microsoft.Extensions.Logging;
using NPOI.SS.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Performance.Services.ExtractExcelService.SheetDataWrite
{
    public class CustomDataWrite : IAutoInjection
    {
        private readonly ILogger<CustomDataWrite> logger;
        private readonly PerforHospitalconfigRepository hospitalconfigRepository;
        private readonly PerforExmoduleRepository exmoduleRepository;
        private readonly PerforExscriptRepository exscriptRepository;
        private readonly CustomExtractService customExtractService;

        public CustomDataWrite(
            ILogger<CustomDataWrite> logger,
            PerforHospitalconfigRepository hospitalconfigRepository,
            PerforExmoduleRepository exmoduleRepository,
            PerforExscriptRepository exscriptRepository,
            CustomExtractService customExtractService
            )
        {
            this.logger = logger;
            this.hospitalconfigRepository = hospitalconfigRepository;
            this.exmoduleRepository = exmoduleRepository;
            this.exscriptRepository = exscriptRepository;
            this.customExtractService = customExtractService;
        }

        public PerSheetPoint Point => new PerSheetPoint
        {
            HeaderFirstRowNum = 1,
            HeaderFirstCellNum = 6,
            DataFirstRowNum = 2,
            DataFirstCellNum = 6,
        };

        public void WriteDataToCustom(IWorkbook workbook, per_allot allot, ExcelStyle style)
        {
            var modules = exmoduleRepository.GetEntities(t => t.SheetType == (int)SheetType.Custom)?.OrderBy(t => t.ModuleName);
            if (modules == null || !modules.Any()) return;

            var exscripts = exscriptRepository.GetEntities(t => modules.Select(s => s.TypeId).Contains(t.TypeId));
            if (exscripts == null || !exscripts.Any()) return;

            var configs = hospitalconfigRepository.GetEntities(t => t.HospitalId == allot.HospitalId);
            if (configs == null || !configs.Any()) throw new Exception("医院未配置绩效抽取信息");

            var parameters = customExtractService.GetParameters(allot);
            var headerStyle = style.SetBgkColorAndFormat(style.GetCellStyle(), StyleType.列头);
            var cellStyle = style.SetBgkColorAndFormat(style.GetCellStyle(), StyleType.数据);

            foreach (var module in modules)
            {
                var sheet = workbook.GetSheet(module.ModuleName) ?? workbook.GetSheet(module.ModuleName.NoBlank());
                if (sheet == null)
                {
                    sheet = workbook.CreateSheet(module.ModuleName);
                    workbook.SetSheetOrder(sheet.SheetName, workbook.NumberOfSheets - 1);
                }
                ClearSheetData(sheet);
                var exscript = exscripts.FirstOrDefault(t => t.TypeId == module.TypeId);
                if (exscript == null) continue;

                var conf = configs.FirstOrDefault(w => w.Id == (module.ConfigId ?? exscript.ConfigId));
                if (conf == null) continue;

                var execsql = exscript.ExecScript;
                var dynamics = customExtractService.QueryData(conf, execsql, parameters);

                try
                {
                    // 没数据跳过
                    if (dynamics == null || dynamics.Count() == 0)
                        continue;

                    var first = (IDictionary<string, object>)dynamics.ElementAt(0);
                    var header = sheet.GetOrCreate(Point.HeaderFirstRowNum.Value);
                    if (header != null)
                    {
                        var cellindex = Point.HeaderFirstCellNum.Value;
                        foreach (var item in first)
                        {
                            var cell = header.GetOrCreate(cellindex);
                            cell.SetCellOValue(item.Key);
                            cell.CellStyle = headerStyle;
                            cellindex++;
                        }
                    }

                    var rowindex = Point.DataFirstRowNum.Value;
                    for (int r = 0; r < dynamics.Count(); r++)
                    {
                        var temp = (IDictionary<string, object>)dynamics.ElementAt(r); // 行数据

                        var row = sheet.GetOrCreate(rowindex);
                        var cellindex = Point.DataFirstCellNum.Value;
                        foreach (var item in temp)
                        {
                            var cell = row.GetOrCreate(cellindex);
                            cell.SetCellOValue(item.Value);
                            cell.CellStyle = cellStyle;
                            cellindex++;
                        }
                        rowindex++;
                    }
                }
                catch (Exception ex)
                {
                    logger.LogError($"自定义模板 - {sheet.SheetName}抽取异常：" + ex);
                }
            }
        }

        private void ClearSheetData(ISheet sheet)
        {
            try
            {
                for (int i = Point.DataFirstRowNum.Value; i < sheet.LastRowNum + 1; i++)
                {
                    var row = sheet.GetRow(i);
                    if (row != null)
                    {
                        row.ZeroHeight = false; //取消隐藏行
                        int dataFirstCellRowNum = Point.DataFirstCellNum.Value;
                        //跳过核算单元和科室
                        for (int j = dataFirstCellRowNum; j < row.LastCellNum; j++)
                        {
                            var cell = row.GetCell(j);
                            if (cell != null && cell.CellType != CellType.Formula)
                            {
                                cell.RemoveCellComment();
                                row.RemoveCell(cell);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
            }
        }
    }
}
