using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System.Collections;
using System.Globalization;

namespace IRaCIS.Core.Application.Service;

public static class ExcelExportHelper
{
    //MiniExcel_Export
    /// <summary>
    /// 
    /// </summary>
    /// <param name="code"></param>
    /// <param name="data"></param>
    /// <param name="exportFileNamePrefix">文件名前缀</param>
    /// <param name="_commonDocumentRepository"></param>
    /// <param name="_hostEnvironment"></param>
    /// <param name="_dictionaryService"></param>
    /// <param name="translateType"></param>
    /// <param name="criterionType"></param>
    /// <returns></returns>
    public static async Task<IActionResult> DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
    {
        var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;

        //判断是否有字典翻译
        object translateData = data;

        if (_dictionaryService != null && translateType != null)
        {
            //一个值 对应不同的字典翻译
            var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
                .SelectMany(c =>
                c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false).Select(f => (DictionaryTranslateAttribute?)f).Where(t => t?.CriterionType == criterionType || t?.CriterionType == null)
                .Select(k => new { c.Name, k.DicParentCode, k.IsTranslateDenpendOtherProperty, k.DependPropertyName, k.DependPropertyValueStr })
                ).ToList();



            //字典表查询出所有需要翻译的数据

            var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslatePropertyList.Select(t => t.DicParentCode).Distinct().ToArray());


            var dic = data.ConvertToDictionary();


            foreach (var key in dic.Keys)
            {
                //是数组 那么找到对应的属性 进行翻译
                if (dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
                {

                    var newObjList = new List<object>();
                    var no = 1;

                    foreach (var item in dic[key] as IList)
                    {
                        var itemDic = item.ConvertToDictionary();

                        //处理集合里面时间类型，根据当前语言将时间转变为字符串
                        foreach (var itemValuePair in itemDic)
                        {
                            if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
                            {
                                itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
                            }
                        }


                        foreach (var needTranslateProperty in needTranslatePropertyList)
                        {
                            //翻译的属性依赖其他属性
                            if (needTranslateProperty.IsTranslateDenpendOtherProperty)
                            {
                                if (itemDic[needTranslateProperty.DependPropertyName]?.ToString().ToLower() == needTranslateProperty.DependPropertyValueStr.ToLower())
                                {
                                    var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();

                                    itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
                                }
                            }
                            //普通翻译 或者某一标准翻译
                            else
                            {
                                var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();


                                itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
                            }



                        }

                        itemDic.Add("No", no++);


                        newObjList.Add(itemDic);
                    }

                    dic[key] = newObjList;

                }

            }


            //data = dic;

            translateData = dic;

        }





        var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);


        //模板路径
        var tplPath = physicalPath;

        #region 根据中英文  删除模板sheet

        // 打开模板文件
        var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);

        // 获取文件流
        var templateStream = new MemoryStream();
        templateFile.CopyTo(templateStream);
        templateStream.Seek(0, SeekOrigin.Begin);

        var workbook = new XSSFWorkbook(templateStream);

        int sheetCount = workbook.NumberOfSheets;

        if (sheetCount == 2)
        {
            if (isEn_US)
            {
                workbook.RemoveSheetAt(0);
            }
            else
            {
                workbook.RemoveSheetAt(1);
            }

            var memoryStream2 = new MemoryStream();
            workbook.Write(memoryStream2, true);

            memoryStream2.Seek(0, SeekOrigin.Begin);

            templateStream = memoryStream2;
        }

        // 文件名称 从sheet里面取
        //fileNmae = workbook.GetSheetName(0);
        #endregion

        #region MiniExcel

        var memoryStream = new MemoryStream();

        var config = new OpenXmlConfiguration()
        {
            IgnoreTemplateParameterMissing = true,
        };

        await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);

        memoryStream.Seek(0, SeekOrigin.Begin);


        return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        {
            FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
        };

        #endregion

    }

    public class DynamicColumnConfig
    {
        /// <summary>
        /// 增加动态列开始索引  从0 开始算 
        /// </summary>
        public int AutoColumnStartIndex { get; set; }

        /// <summary>
        /// 动态列开始的行index 从0开始
        /// </summary>
        public int AutoColumnTitleRowIndex { get; set; }


        public int TempalteLastColumnIndex { get; set; }

        /// <summary>
        /// 动态的列名
        /// </summary>
        public List<string> ColumnNameList { get; set; } = new List<string>();

        /// <summary>
        /// 动态翻译的字典名
        /// </summary>
        public List<string> TranslateDicNameList { get; set; } = new List<string>();

        /// <summary>
        /// 动态取数据的集合名
        /// </summary>
        public string DynamicListName { get; set; }


        /// <summary>
        /// 动态数据翻译的取字典的属性名
        /// </summary>
        public string DynamicItemDicName { get; set; }
        /// <summary>
        /// 取值的属性名
        /// </summary>
        public string DynamicItemValueName { get; set; }

        public List<int> RemoveColunmIndexList { get; set; } = new List<int>();
    }


    public static async Task<(MemoryStream, string)> DataExport_NpoiTestAsync(string code, ExcelExportInfo data, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null, DynamicColumnConfig? dynamicColumnConfig = null)
    {
        var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
        //判断是否有字典翻译

        object translateData = data;

        Dictionary<string, object> translatedDic = default;

        if (_dictionaryService != null && translateType != null)
        {

            //一个值 对应不同的字典翻译
            var needTranslatePropertyList = translateType.GetProperties().Where(t => t.IsDefined(typeof(DictionaryTranslateAttribute), true))
                .SelectMany(c =>
                c.GetCustomAttributes(typeof(DictionaryTranslateAttribute), false).Select(f => (DictionaryTranslateAttribute?)f).Where(t => t.CriterionType == criterionType || t.CriterionType == null)
                .Select(k => new { c.Name, k.DicParentCode, k.IsTranslateDenpendOtherProperty, k.DependPropertyName, k.DependPropertyValueStr })
                ).ToList();



            //字典表查询出所有需要翻译的数据

            var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslatePropertyList.Select(t => t.DicParentCode).Distinct().ToArray());

            var dic = data.ConvertToDictionary();
            //var dic = (JsonConvert.DeserializeObject<IDictionary<string, object>>(data.ToJsonNotIgnoreNull())).IfNullThrowException();

            foreach (var key in dic.Keys)
            {
                //是数组 那么找到对应的属性 进行翻译
                if (dic[key].GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)))
                //if (dic[key].GetType().IsAssignableFrom(typeof(JArray)))
                {

                    var newObjList = new List<object>();
                    var no = 1;
                    foreach (var item in dic[key] as IList)
                    //foreach (var item in dic[key] as JArray)
                    {
                        //var itemDic = JsonConvert.DeserializeObject<IDictionary<string, object>>(item.ToJsonNotIgnoreNull());
                        var itemDic = item.ConvertToDictionary();

                        //处理集合里面时间类型，根据当前语言将时间转变为字符串
                        foreach (var itemValuePair in itemDic)
                        {
                            if (DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
                            {
                                itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
                            }
                        }

                        foreach (var needTranslateProperty in needTranslatePropertyList)
                        {
                            //翻译的属性依赖其他属性
                            if (needTranslateProperty.IsTranslateDenpendOtherProperty)
                            {
                                if (itemDic[needTranslateProperty.DependPropertyName]?.ToString().ToLower() == needTranslateProperty.DependPropertyValueStr.ToLower())
                                {
                                    var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();

                                    itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
                                }
                            }
                            //普通翻译 或者某一标准翻译
                            else
                            {
                                var beforeValue = itemDic[needTranslateProperty.Name]?.ToString();


                                itemDic[needTranslateProperty.Name] = translateDataList[needTranslateProperty.DicParentCode].Where(t => t.Code.ToLower() == beforeValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
                            }



                        }

                        itemDic.Add("No", no++);
                        newObjList.Add(itemDic);
                    }

                    dic[key] = newObjList;

                }
            }


            //data = dic;
            translateData = dic;
            translatedDic = dic;

        }


        var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);


        //模板路径
        var tplPath = physicalPath;

        #region 根据中英文  删除模板sheet

        // 打开模板文件
        var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);

        // 获取文件流
        var templateStream = new MemoryStream();
        templateFile.CopyTo(templateStream);
        templateStream.Seek(0, SeekOrigin.Begin);

        var workbook = new XSSFWorkbook(templateStream);

        int sheetCount = workbook.NumberOfSheets;

        if (sheetCount == 2)
        {
            if (isEn_US)
            {
                workbook.RemoveSheetAt(0);
            }
            else
            {
                workbook.RemoveSheetAt(1);
            }


            if (dynamicColumnConfig != null)
            {
                var sheet = workbook.GetSheetAt(0);

                var titelRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex);
                var templateRow = sheet.GetRow(dynamicColumnConfig.AutoColumnTitleRowIndex + 1);

                //动态移除列的数量
                var dynamicRemoveColunmCount = dynamicColumnConfig.RemoveColunmIndexList.Count();

                var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Where(t => t < dynamicColumnConfig.AutoColumnStartIndex).Count();

                //动态添加列的数量
                var needAddCount = dynamicColumnConfig.ColumnNameList.Count;

                //原始表  最终索引
                var originTotalEndIndex = dynamicColumnConfig.TempalteLastColumnIndex;

                var originRemoveEndIndex= originTotalEndIndex- dynamicRemoveColunmCount;

                //最终表 动态列开始索引
                var dynamicColunmStartIndex = dynamicColumnConfig.AutoColumnStartIndex - beforeDynamicRemoveCount;

                //最终表 动态列的终止索引
                var dynamicColunmEndIndex = dynamicColunmStartIndex + needAddCount - 1;

                //最终表  最终索引
                var totalColunmEndIndex = originTotalEndIndex + needAddCount - dynamicRemoveColunmCount;


                //动态列后需要移动的数量
                var backMoveCount = totalColunmEndIndex - dynamicColunmEndIndex;

                //删除需要动态删除的列  从大到小移除，否则索引会变
                foreach (var removeIndex in dynamicColumnConfig.RemoveColunmIndexList.OrderByDescending(t => t))
                {
                    //将后面的列向前移动
                    for (var i = 0; i < originTotalEndIndex - removeIndex; i++)
                    {
                        Console.WriteLine(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
                        titelRow.GetCell(removeIndex + i).SetCellValue(titelRow.GetCell(removeIndex + i + 1).StringCellValue);
                        templateRow.GetCell(removeIndex + i).SetCellValue(templateRow.GetCell(removeIndex + i + 1).StringCellValue);

                        //后面的数据要清空
                        titelRow.GetCell(removeIndex + i + 1).SetCellValue("");
                        templateRow.GetCell(removeIndex + i + 1).SetCellValue("");

                    }

                }

                //创建新的列
                for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
                {
                    titelRow.CreateCell(i + 1);
                }
                //移动Title 和下面的模板标识

                var gap = totalColunmEndIndex - originRemoveEndIndex;

                for (int i = totalColunmEndIndex; i > dynamicColunmEndIndex; i--)
                {

                    titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);

                    templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
                }



                //设置动态Tilte

                for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
                {
                    var name = dynamicColumnConfig.ColumnNameList[i - dynamicColunmStartIndex];

                    titelRow.GetCell(i).SetCellValue(name);
                }
            }

            using (var memoryStream2 = new MemoryStream())
            {
                workbook.Write(memoryStream2, true);

                memoryStream2.Seek(0, SeekOrigin.Begin);

                templateStream = memoryStream2;
            }


        }

        #endregion

        #region MiniExcel

        var memoryStream = new MemoryStream();

        var config = new OpenXmlConfiguration()
        {
            IgnoreTemplateParameterMissing = true,
        };

        await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);

        memoryStream.Seek(0, SeekOrigin.Begin);

        if (dynamicColumnConfig != null)
        {
            var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());

            // 使用NPOI  进行二次处理
            var wb = new XSSFWorkbook(memoryStream);
            var sheet = wb.GetSheetAt(0);

            var list = translatedDic["List"] as IList;

            foreach (var itemResult in list)
            {
                var index = list.IndexOf(itemResult);

                //从第四行开始处理动态列
                var row = sheet.GetRow(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);

                var itemDic = itemResult.ToDictionary();

                var itemList = itemDic[dynamicColumnConfig.DynamicListName] as IList;

                foreach (var itemObj in itemList)
                {
                    var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;

                    var iteObjDic = itemObj.ToDictionary();

                    var itemDicName = iteObjDic[dynamicColumnConfig.DynamicItemDicName].ToString();
                    var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName].ToString();

                    if (itemDicName.IsNotNullOrEmpty())
                    {

                        var translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;

                        row.GetCell(writeIndex).SetCellValue(translatedItemData);
                    }
                    else
                    {
                        row.GetCell(writeIndex).SetCellValue(itemValue);

                    }

                }
            }

            var memoryStream2 = new MemoryStream();
            wb.Write(memoryStream2, true);
            memoryStream2.Seek(0, SeekOrigin.Begin);

            memoryStream = memoryStream2;

        }


        return (memoryStream, fileName);




        #endregion
    }


    /// <summary>
    /// 导出文件模板
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    public static async Task<FileResult> ExportTemplateAsync(ExportTemplateServiceDto inDto)
    {
        var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(inDto.hostEnvironment, inDto.commonDocumentRepository, inDto.TemplateCode);


        //模板路径
        var tplPath = physicalPath;

        #region 根据中英文  删除模板sheet

        // 打开模板文件
        var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);

        // 获取文件流
        var templateStream = new MemoryStream();
        templateFile.CopyTo(templateStream);
        templateStream.Seek(0, SeekOrigin.Begin);

        var workbook = new XSSFWorkbook(templateStream);

        int sheetCount = workbook.NumberOfSheets;

        if (sheetCount == 2)
        {
            if (inDto.IsEnglish)
            {
                workbook.RemoveSheetAt(0);
            }
            else
            {
                workbook.RemoveSheetAt(1);
            }


        }

        #endregion


        ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表



        for (int i = 0; i < sheet.LastRowNum + 1; i++)
        {
            IRow row = sheet.GetRow(i);
            for (int j = 0; j < sheet.LastRowNum; j++)
            {
                ICell cell = row.GetCell(j);
                foreach (var property in inDto.Data.GetType().GetProperties())
                {
                    var value = property.GetValue(inDto.Data);
                    if (cell != null && cell.ToString() == "{{" + property.Name + "}}")
                    {
                        sheet.GetRow(i).GetCell(j).SetCellValue(value.ToString());
                    }
                }
            }
        }



        var memoryStream2 = new MemoryStream();
        workbook.Write(memoryStream2, true);

        memoryStream2.Seek(0, SeekOrigin.Begin);

        templateStream = memoryStream2;


        return new FileStreamResult(templateStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        {
            FileDownloadName = $"{(string.IsNullOrEmpty(inDto.ExportFileName) ? "" : inDto.ExportFileName + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
        };
    }

}