using ClosedXML.Excel;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using Newtonsoft.Json;
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, List<int> removeExcelIndexList = 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] != null && 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)
                        //{
                        //    // 临床数据 1，1 会变成2024-01-01
                        //    if (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
                        //    {
                        //        itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
                        //    }
                        //}


                        foreach (var needTranslateProperty in needTranslatePropertyList)
                        {
                            if (itemDic.Keys.Any(t => t == needTranslateProperty.Name))
                            {
                                //翻译的属性依赖其他属性
                                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

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

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

        using var workbook = new XLWorkbook(templateStream);

        int sheetCount = workbook.Worksheets.Count;

        if (sheetCount == 2)
        {
            if (isEn_US)
            {
                workbook.Worksheets.Delete(1);  // 删除第1个（索引1）
            }
            else
            {
                workbook.Worksheets.Delete(2);  // 删除第2个（索引2）
            }

            if (removeExcelIndexList != null)
            {
                var worksheet = workbook.Worksheet(1);  // 索引从1开始
                foreach (int colIndex in removeExcelIndexList.OrderByDescending(t => t))
                {
                    // 删除整列
                    worksheet.Column(colIndex).Delete();
                }
            }


            //中文替换项目术语
            if (data.TrialObjectNameList?.Count > 0)
            {
                var replaceObjectList = data.TrialObjectNameList;

                // ClosedXML 获取第一个工作表
                var worksheet = workbook.Worksheet(1);  // 索引从1开始

                #region sheet 名字修改 以及导表文件名字修改

                var currentSheetName = worksheet.Name;

                // 查找匹配的工作表名（支持部分匹配）
                var findObj = replaceObjectList.FirstOrDefault(t => currentSheetName.Contains(t.Name));

                if (findObj != null)
                {
                    // 直接匹配或替换包含关键字的工作表名
                    var newSheetName = currentSheetName.Replace(findObj.Name, findObj.TrialName);
                    worksheet.Name = newSheetName;
                }


                var findFileName = replaceObjectList.FirstOrDefault(t => fileName.Contains(t.Name));

                if (findFileName != null)
                {
                    // 直接匹配或替换包含关键字的工作表名
                    var newFileName = currentSheetName.Replace(findFileName.Name, findFileName.TrialName);
                    fileName = newFileName;
                }
                #endregion

                // 获取使用的行范围（不包括空行）
                var rowsUsed = worksheet.RowsUsed();

                foreach (var row in rowsUsed)
                {
                    // 获取该行有数据的单元格
                    var cellsUsed = row.CellsUsed(c => c.DataType == XLDataType.Text);

                    foreach (var cell in cellsUsed)
                    {
                        var cellValue = cell.GetString();

                        var newValue = cellValue;
                        var isChanged = false;

                        var find = replaceObjectList.FirstOrDefault(t => cellValue.Trim() == t.Name.Trim());

                        if (find != null)
                        {
                            newValue = newValue.Replace(find.Name, find.TrialName);

                            isChanged = true;
                        }
                        else
                        {
                            // 遍历所有替换规则，进行关键字匹配替换
                            foreach (var replaceItem in replaceObjectList.Where(t => cellValue.Contains(t.Name)))
                            {

                                newValue = newValue.Replace(replaceItem.Name, replaceItem.TrialName);
                                isChanged = true;
                            }
                        }


                        if (isChanged)
                        {
                            cell.SetValue(newValue);
                        }


                    }
                }
            }

            using (var memoryStream2 = new MemoryStream())
            {
                workbook.SaveAs(memoryStream2);
                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>
        /// 增加动态列开始索引   npoi从0开始  现在ClosedXML 从1开始
        /// </summary>
        public int AutoColumnStartIndex { get; set; }

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

        /// <summary>
        /// 模板列最后的索引  npoi从0开始  现在ClosedXML 从1开始
        /// </summary>
        public int TempalteLastColumnIndex { get; set; }

        public bool IsCDISCExport { get; set; } = false;

        //public List<string> CDISCList { get; set; } = new List<string>();

        /// <summary>
        /// 动态的列名  如果Id 重复，那么就按照名称填充，否则就按照Id 填充列数据
        /// </summary>
        public List<ColumItem> ColumnIdNameList { get; set; }

        /// <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; }

        /// <summary>
        /// Excel Title Name
        /// </summary>
        public string DynamicItemTitleName { get; set; }

        public string DynamicItemTitleId { get; set; }

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

        public class ColumItem
        {
            public Guid Id { get; set; }
            public string Name { get; set; }

            public string CDISCCode { get; set; }

            public override bool Equals(object obj)
            {
                if (obj is not ColumItem other) return false;
                return Id == other.Id && Name == other.Name;
            }

            public override int GetHashCode()
            {
                return HashCode.Combine(Id, Name);
            }
        }

        public List<string> ColumnIdList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Id.ToString()).ToList();
        public List<string> ColumnNameList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Name).ToList();
    }


    public static async Task<(MemoryStream, string)> DataExport_ClosedXMLAsync(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] != null && 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 (itemValuePair.Value?.ToString().Length > 8 && DateTime.TryParse(itemValuePair.Value?.ToString(), out DateTime result))
                        //    {
                        //        itemDic[itemValuePair.Key] = ExportExcelConverterDate.DateTimeInternationalToString(result);
                        //    }
                        //}

                        foreach (var needTranslateProperty in needTranslatePropertyList)
                        {
                            if (itemDic.Keys.Any(t => t == needTranslateProperty.Name))
                            {
                                //翻译的属性依赖其他属性
                                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);


        using var workbook = new XLWorkbook(templateStream);

        int sheetCount = workbook.Worksheets.Count;

        if (sheetCount == 2)
        {
            if (isEn_US)
            {
                workbook.Worksheets.Delete(1);  // 删除第1个（索引1）
            }
            else
            {
                workbook.Worksheets.Delete(2);  // 删除第2个（索引2）
            }

            #region 中文替换项目术语
            //中文替换项目术语
            if (data.TrialObjectNameList?.Count > 0)
            {
                var replaceObjectList = data.TrialObjectNameList;

                // ClosedXML 获取第一个工作表
                var worksheet = workbook.Worksheet(1);  // 索引从1开始

                #region sheet 名字修改 以及导表文件名字修改

                var currentSheetName = worksheet.Name;

                // 查找匹配的工作表名（支持部分匹配）
                var findObj = replaceObjectList.FirstOrDefault(t => currentSheetName.Contains(t.Name));

                if (findObj != null)
                {
                    // 直接匹配或替换包含关键字的工作表名
                    var newSheetName = currentSheetName.Replace(findObj.Name, findObj.TrialName);
                    worksheet.Name = newSheetName;
                }


                var findFileName = replaceObjectList.FirstOrDefault(t => fileName.Contains(t.Name));

                if (findFileName != null)
                {
                    // 直接匹配或替换包含关键字的工作表名
                    var newFileName = currentSheetName.Replace(findFileName.Name, findFileName.TrialName);
                    fileName = newFileName;
                }
                #endregion

                // 获取使用的行范围（不包括空行）
                var rowsUsed = worksheet.RowsUsed();

                foreach (var row in rowsUsed)
                {
                    // 获取该行有数据的单元格
                    var cellsUsed = row.CellsUsed(c => c.DataType == XLDataType.Text);

                    foreach (var cell in cellsUsed)
                    {
                        var cellValue = cell.GetString();

                        var newValue = cellValue;
                        var isChanged = false;

                        var find = replaceObjectList.FirstOrDefault(t => cellValue.Trim() == t.Name.Trim());

                        if (find != null)
                        {
                            newValue = newValue.Replace(find.Name, find.TrialName);

                            isChanged = true;
                        }
                        else
                        {
                            // 遍历所有替换规则，进行关键字匹配替换
                            foreach (var replaceItem in replaceObjectList.Where(t => cellValue.Contains(t.Name)))
                            {

                                newValue = newValue.Replace(replaceItem.Name, replaceItem.TrialName);
                                isChanged = true;
                            }
                        }


                        if (isChanged)
                        {
                            cell.SetValue(newValue);
                        }


                    }
                }
            }

            #endregion


            if (dynamicColumnConfig != null)
            {
                var isCdics = dynamicColumnConfig.IsCDISCExport;

                // ClosedXML 获取工作表（索引从1开始）
                var worksheet = workbook.Worksheet(1);

                // 获取行（ClosedXML 行索引从1开始，AutoColumnTitleRowIndex 已经改了保持不变）
                var cdicsRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex - 1);      // 原 NPOI: -1
                var titelRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex);  // 原 NPOI: 不变
                var templateRow = worksheet.Row(dynamicColumnConfig.AutoColumnTitleRowIndex + 1); // 原 NPOI: +1

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

                // 在动态列开始前移除的数量
                var beforeDynamicRemoveCount = dynamicColumnConfig.RemoveColunmIndexList.Count(t => t < dynamicColumnConfig.AutoColumnStartIndex);

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

                // 原始表最终索引（NPOI 从0开始，ClosedXML 从1开始，但这里存储的是逻辑索引，后续转换）
                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;

                // 删除需要动态删除的列（从大到小移除，否则索引会变）
                // 注意：ClosedXML 可以直接使用 Delete() 方法，但为了保持原逻辑，这里使用手动移动
                foreach (var removeIndex in dynamicColumnConfig.RemoveColunmIndexList.OrderByDescending(t => t))
                {
                    // 将后面的列向前移动
                    for (var i = 0; i < originTotalEndIndex - removeIndex; i++)
                    {

                        int currentCol = removeIndex + i;
                        int nextCol = removeIndex + i + 1;

                        Console.WriteLine(titelRow.Cell(nextCol).GetString());

                        // 移动值
                        titelRow.Cell(currentCol).SetValue(titelRow.Cell(nextCol).GetString());
                        templateRow.Cell(currentCol).SetValue(templateRow.Cell(nextCol).GetString());

                        // 清空后面的数据
                        titelRow.Cell(nextCol).SetValue(string.Empty);
                        templateRow.Cell(nextCol).SetValue(string.Empty);
                    }
                }

                // 创建新的列（ClosedXML 不需要显式创建，直接设置值即可）
                for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
                {
                    int colIndex = i + 1;

                    // 不需要 CreateCell，直接设置值即可
                    if (isCdics)
                    {
                        cdicsRow.Cell(colIndex).SetValue(string.Empty);
                    }
                    titelRow.Cell(colIndex).SetValue(string.Empty);
                    templateRow.Cell(colIndex).SetValue(string.Empty);
                }

                // 移动 Title 和下面的模板标识
                var gap = totalColunmEndIndex - originRemoveEndIndex;

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

                    titelRow.Cell(currentCol).SetValue(titelRow.Cell(sourceCol).GetString());
                    templateRow.Cell(currentCol).SetValue(templateRow.Cell(sourceCol).GetString());

                    if (isCdics)
                    {
                        cdicsRow.Cell(currentCol).SetValue(cdicsRow.Cell(sourceCol).GetString());
                    }
                }

                // 设置动态 Title
                for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
                {
                    int colIndex = i;
                    var index = i - dynamicColunmStartIndex;
                    var name = dynamicColumnConfig.ColumnIdNameList[index].Name;

                    titelRow.Cell(colIndex).SetValue(name);
                    templateRow.Cell(colIndex).SetValue(string.Empty);

                    if (isCdics)
                    {
                        var cdicsCode = dynamicColumnConfig.ColumnIdNameList[index].CDISCCode;
                        cdicsRow.Cell(colIndex).SetValue(cdicsCode);
                    }
                }
            }

            using (var memoryStream2 = new MemoryStream())
            {
                workbook.SaveAs(memoryStream2);
                memoryStream2.Seek(0, SeekOrigin.Begin);
                templateStream = memoryStream2;
            }

        }

        #endregion

        #region MiniExcel

        var memoryStream = new MemoryStream();

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

        //await MiniExcel.SaveAsByTemplateAsync("testmini.xlsx", templateStream.ToArray(), translateData);

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


        memoryStream.Seek(0, SeekOrigin.Begin);

        if (dynamicColumnConfig != null)
        {
            //Excel 列是按照名称填充 还是Id 填充
            var isExcelAddDataWithName = dynamicColumnConfig.ColumnIdNameList.Select(t => t.Id).Distinct().Count() == 1;

            var dynamicTranslateDataList = await _dictionaryService.GetBasicDataSelect(dynamicColumnConfig.TranslateDicNameList.ToArray());

            // 使用 ClosedXML 进行二次处理
            using var wb = new XLWorkbook(memoryStream);
            var worksheet = wb.Worksheet(1);  // 获取第一个工作表，索引从1开始

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

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

                // 从第四行开始处理动态列
                var row = worksheet.Row(index + dynamicColumnConfig.AutoColumnTitleRowIndex + 1);  // +2 因为 NPOI 从0，ClosedXML 从1

                var itemDic = itemResult.ToDictionary();

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

                //这个数组是动态的，有的多，有的少，所以在此对比Title 一致才赋值
                foreach (var itemObj in itemList)
                {

                    var iteObjDic = itemObj.ToDictionary();

                    var itemDicName = iteObjDic.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString() : "";
                    var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();

                    //var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;

                    var writeIndex = 0;

                    if (isExcelAddDataWithName)
                    {
                        writeIndex = dynamicColumnConfig.ColumnNameList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleName].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;  // +1 因为 ClosedXML 列从1开始
                    }
                    else
                    {
                        writeIndex = dynamicColumnConfig.ColumnIdList.IndexOf(iteObjDic[dynamicColumnConfig.DynamicItemTitleId].ToString()) + dynamicColumnConfig.AutoColumnStartIndex;  // +1 因为 ClosedXML 列从1开始
                    }


                    if (itemDicName.IsNotNullOrEmpty())
                    {

                        var optionTypeEnumStr = iteObjDic.ContainsKey("OptionTypeEnum") ? iteObjDic["OptionTypeEnum"]?.ToString() : "0";

                        var translatedItemData = "";
                        //多选
                        if (optionTypeEnumStr == "1")
                        {
                            int[] enumValues = new int[0];
                            // 1. 反序列化 JSON 数组 (字符串枚举)
                            if (!itemValue.StartsWith("[") || !itemValue.EndsWith("]"))
                            {
                                enumValues = new int[1] { int.Parse(itemValue) };
                            }
                            else
                            {
                                enumValues = JsonConvert.DeserializeObject<int[]>(itemValue) ?? new int[0];

                            }


                            // 2. 翻译每一项并输出逗号拼接字符串
                            translatedItemData = string.Join(",",
                                enumValues.Select(code =>
                                    dynamicTranslateDataList[itemDicName]
                                        .FirstOrDefault(t =>
                                           string.Equals(code.ToString(), t.Code, StringComparison.OrdinalIgnoreCase)
                                        ) is var r && r != null
                                            ? (isEn_US ? r.Value : r.ValueCN)
                                            : string.Empty
                                ));
                        }
                        else
                        {

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

                        }

                        // ClosedXML 设置单元格值
                        row.Cell(writeIndex).SetValue(translatedItemData);

                    }
                    else
                    {
                        var unit = iteObjDic.ContainsKey("Unit") ? iteObjDic["Unit"]?.ToString() : null;

                        if (unit.IsNotNullOrEmpty() && unit == "9")
                        {
                            row.Cell(writeIndex).SetValue(itemValue + "%");
                        }
                        else
                        {
                            row.Cell(writeIndex).SetValue(itemValue);
                        }


                    }

                }
            }

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

            memoryStream = memoryStream2;

        }


        return (memoryStream, fileName);




        #endregion
    }




    public static async Task<IActionResult> MutiSheetDataExportAsync(string code, object data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment)
    {

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


        //模板路径
        var tplPath = physicalPath;

        var templateStream = new MemoryStream();


        #region npoi 移除某一行
        var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;

        if (isEn_US)
        {
            // 打开模板文件
            using var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);

            using var workbook = new XLWorkbook(templateFileStream);

            int sheetCount = workbook.Worksheets.Count;

            int removeRowIndex = 2; // ClosedXML 中行索引从 1 开始，所以第2行对应 NPOI 的第1行

            for (int i = 1; i <= sheetCount; i++)  // ClosedXML 工作表索引从 1 开始
            {
                var worksheet = workbook.Worksheet(i);

                // 删除行
                var row = worksheet.Row(removeRowIndex);
                if (!row.IsEmpty() || row.CellsUsed().Any())  // 检查行是否存在数据
                {
                    row.Delete();  // ClosedXML 直接删除行
                }
            }

            workbook.SaveAs(templateStream);
            templateStream.Position = 0;


        }
        else
        {
            using (var fs = new FileStream(tplPath, FileMode.Open, FileAccess.Read))
            {
                fs.CopyTo(templateStream);
            }

            templateStream.Position = 0;
        }


        #endregion


        var memoryStream = new MemoryStream();

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

        await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), data, 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"
        };
    }

    /// <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（使用 ClosedXML）

        using var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
        using var workbook = new XLWorkbook(templateFileStream);

        int sheetCount = workbook.Worksheets.Count;

        //if (sheetCount == 2)
        //{
        if (inDto.IsEnglish)
        {
            workbook.Worksheet(1).Delete();  // 删除第一个工作表
        }
        else
        {
            workbook.Worksheet(2).Delete();  // 删除第二个工作表
        }
        //}

        #endregion

        // 获取第一个工作表（删除后剩下的那个）
        var worksheet = workbook.Worksheet(1);

        // 遍历所有行和列，替换模板占位符
        var rowsUsed = worksheet.RowsUsed();

        foreach (var row in rowsUsed)
        {
            var cellsUsed = row.CellsUsed(c => c.DataType == XLDataType.Text);

            foreach (var cell in cellsUsed)
            {
                var cellValue = cell.GetString();

                // 检查是否包含模板占位符 {{PropertyName}}
                foreach (var property in inDto.Data.GetType().GetProperties())
                {
                    var placeholder = "{{" + property.Name + "}}";
                    if (cellValue.Contains(placeholder))
                    {
                        var value = property.GetValue(inDto.Data);
                        var newValue = cellValue.Replace(placeholder, value?.ToString() ?? string.Empty);
                        cell.SetValue(newValue);
                    }
                }
            }
        }

        var memoryStream = new MemoryStream();
        workbook.SaveAs(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);

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

    }




}