
using DocumentFormat.OpenXml.ExtendedProperties;
using Hotline.Application.Tools;
using Hotline.Share.Dtos.CallCenter;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Article;
using Hotline.Share.Tools;
using Hotline.Tools;
using Mapster;
using MapsterMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using MiniExcelLibs;
using NPOI.HPSF;
using NPOI.SS.Formula.Functions;
using SqlSugar;
using System.Net.Http;
using System.Reflection;
using XF.Domain.Dependency;
using XF.Utility.EnumExtensions;

namespace Hotline.Application.ExportExcel
{
    public class ExportApplication : IExportApplication, IScopeDependency
    {
        private readonly IMapper _mapper;

        public ExportApplication(IMapper mapper)
        {
            _mapper = mapper;
        }

        /// <summary>
        /// 导出数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">数据集</param>
        /// <param name="name">导出文件名（不传则生成yyyyMMddhhmmss）</param>
        /// <returns></returns>
        public FileStreamResult ExportData<T>(IList<T> list, string? name)
        {
            var stream = new MemoryStream();
            stream.SaveAs(list);
            stream.Seek(0, SeekOrigin.Begin);
            return new FileStreamResult(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
            {
                FileDownloadName = string.IsNullOrEmpty(name) ? DateTime.Now.ToString("yyyyMMddhhmmss") + ".xlsx" : name
            };
        }

        public Stream GetExcelStream<T, D>(ExportExcelDto<D> dto, IList<T> items, Func<IList<T>, T>? func = null)
        {
            if (items != null && items.Count > 0 && func != null)
            {
                items.Add(func.Invoke(items));
            }

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos, typeof(T));

            var dtos = items
                .Select(stu => _mapper.Map(stu, typeof(T), dynamicClass))
                .Cast<object>()
                .ToList();

            return ExcelHelper.CreateStream(dtos);
        }

        public FileStreamResult GetExcelFile<T, D>(ExportExcelDto<D> dto, IList<T> items, string fileName, Func<IList<T>, T>? func = null)
        {
            return GetExcelStream(dto, items, func).GetExcelFile(fileName);
        }

        public FileStreamResult GetExcelFile(Type typeT, Type typeD, object dto, IList<object> items, string fileName, string? totalFiledName)
        {
            if (totalFiledName.IsNullOrEmpty()) return GetExcelFile(typeT, typeD, dto, items, fileName);
            var fieldsAll = typeT.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var fields = fieldsAll.Where(f => IsNumericType(f.FieldType)); // 只选择数值类型字段
            var totalField = fieldsAll.Where(m => m.Name.Contains(totalFiledName)).First();

            var sumDict = new Dictionary<FieldInfo, dynamic>();

            foreach (var field in fields)
            {
                sumDict[field] = 0;
            }

            foreach (var item in items)
            {
                foreach (var field in fields)
                {
                    var value = field.GetValue(item);
                    if (value != null)
                    {
                        sumDict[field] += (dynamic)value; // 使用 dynamic 累加
                    }
                }
            }

            var resultItem = Activator.CreateInstance(typeT);
            totalField.SetValue(resultItem, "合计");
            foreach (var field in fields)
            {
                field.SetValue(resultItem, sumDict[field]);
            }
            items.Add(resultItem);
            return GetExcelFile(typeT, typeD, dto, items, fileName);
        }

        public FileStreamResult GetExcelFile(Type typeT, Type typeD, object dto, IList<object> items, string fileName)
        {
            var columnInfos = typeD.GetProperty("ColumnInfos")?.GetValue(dto) as List<ColumnInfo>;
            if (columnInfos == null)
            {
                throw new ArgumentException("ColumnInfos not found in dto");
            }

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(columnInfos, typeT);

            var dtos = items
                .Select(item =>
                {
                    var mappedItem = _mapper.Map(item, typeT, dynamicClass);
                    foreach (var prop in mappedItem.GetType().GetProperties())
                    {
                        if (prop.PropertyType == typeof(string))
                        {
                            if ((string)prop.GetValue(mappedItem) == "True")
                                prop.SetValue(mappedItem, "是");
                            if ((string)prop.GetValue(mappedItem) == "False")
                                prop.SetValue(mappedItem, "否");
                        }
                    }
                    return mappedItem;
                })
                .Cast<object>()
                .ToList();

            return ExcelHelper.CreateStream(dtos).GetExcelFile(fileName);
        }


        public FileStreamResult GetExcelFile<T, D>(ExportExcelDto<D> dto, IList<T> items, string fileName, string totalName) where T : new()
        {
            var fieldsAll = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var fields = fieldsAll.Where(f => IsNumericType(f.FieldType)); // 只选择数值类型字段
            var totalField = fieldsAll.Where(m => m.Name.Contains(totalName)).First();

            var sumDict = new Dictionary<FieldInfo, dynamic>();

            foreach (var field in fields)
            {
                sumDict[field] = 0;
            }

            foreach (var item in items)
            {
                foreach (var field in fields)
                {
                    var value = field.GetValue(item);
                    if (value != null)
                    {
                        sumDict[field] += (dynamic)value; // 使用 dynamic 累加
                    }
                }
            }

            var resultItem = new T();
            totalField.SetValue(resultItem, "合计");
            foreach (var field in fields)
            {
                field.SetValue(resultItem, sumDict[field]);
            }
            items.Add(resultItem);
            return GetExcelFile(dto, items, fileName);
        }

        private static bool IsNumericType(Type type)
        {
            return type == typeof(int) || type == typeof(float) || type == typeof(double) ||
                   type == typeof(decimal) || type == typeof(long) || type == typeof(short) ||
                   type == typeof(byte) || type == typeof(uint) || type == typeof(ulong) ||
                   type == typeof(ushort) || type == typeof(sbyte) || type == typeof(double?);
        }
    }
}
