using Service.Transaction;

namespace Service.Budget;

public interface IBudgetStatsService
{
    /// <summary>
    /// 获取指定分类的统计信息（月度和年度）
    /// </summary>
    Task<BudgetCategoryStats> GetCategoryStatsAsync(BudgetCategory category, DateTime referenceDate);
}

[UsedImplicitly]
public class BudgetStatsService(
    IBudgetRepository budgetRepository,
    IBudgetArchiveRepository budgetArchiveRepository,
    ITransactionStatisticsService transactionStatisticsService,
    IDateTimeProvider dateTimeProvider,
    ILogger<BudgetStatsService> logger
) : IBudgetStatsService
{
    public async Task<BudgetCategoryStats> GetCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
    {
        logger.LogInformation("开始计算分类统计信息: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}", 
            category, referenceDate);

        var result = new BudgetCategoryStats();

        try
        {
            // 获取月度统计
            logger.LogDebug("开始计算月度统计");
            result.Month = await CalculateMonthlyCategoryStatsAsync(category, referenceDate);
            logger.LogInformation("月度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%", 
                result.Month.Count, result.Month.Limit, result.Month.Current, result.Month.Rate);

            // 获取年度统计
            logger.LogDebug("开始计算年度统计");
            result.Year = await CalculateYearlyCategoryStatsAsync(category, referenceDate);
            logger.LogInformation("年度统计计算完成: Count={Count}, Limit={Limit}, Current={Current}, Rate={Rate:F2}%", 
                result.Year.Count, result.Year.Limit, result.Year.Current, result.Year.Rate);

            logger.LogInformation("分类统计信息计算完成");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "计算分类统计信息时发生错误: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM-dd}", 
                category, referenceDate);
            throw;
        }

        return result;
    }

    private async Task<BudgetStatsDto> CalculateMonthlyCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
    {
        logger.LogDebug("开始计算月度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy-MM}", 
            category, referenceDate);

        var result = new BudgetStatsDto
        {
            PeriodType = BudgetPeriodType.Month,
            Rate = 0,
            Current = 0,
            Limit = 0,
            Count = 0
        };

        // 1. 获取所有预算（包含归档数据）
        logger.LogDebug("开始获取预算数据（包含归档）");
        var budgets = await GetAllBudgetsWithArchiveAsync(category, BudgetPeriodType.Month, referenceDate);
        logger.LogDebug("获取到 {BudgetCount} 个预算", budgets.Count);

        if (budgets.Count == 0)
        {
            logger.LogDebug("未找到相关预算，返回空结果");
            return result;
        }

        result.Count = budgets.Count;

        // 2. 计算限额总值
        logger.LogDebug("开始计算限额总值，共 {BudgetCount} 个预算", budgets.Count);
        decimal totalLimit = 0;
        foreach (var budget in budgets)
        {
            var itemLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Month, referenceDate);
            totalLimit += itemLimit;
        }
        result.Limit = totalLimit;
        logger.LogDebug("限额总值计算完成: {TotalLimit}", totalLimit);

        // 3. 计算当前实际值
        // 使用 GetAllBudgetsWithArchiveAsync 中已经计算好的 Current 值
        var totalCurrent = budgets.Sum(b => b.Current);
        logger.LogInformation("【实际值来源】累加各预算的实际值: {TotalCurrent}元（共{Count}个预算）", totalCurrent, budgets.Count);
        
        var transactionType = category switch
        {
            BudgetCategory.Expense => TransactionType.Expense,
            BudgetCategory.Income => TransactionType.Income,
            _ => TransactionType.None
        };

        // 计算趋势数据（用于图表展示）
        var now = dateTimeProvider.Now;
        var (startDate, endDate) = GetStatPeriodRange(BudgetPeriodType.Month, referenceDate);
        logger.LogDebug("统计时间段: {StartDate:yyyy-MM-dd} 到 {EndDate:yyyy-MM-dd}", startDate, endDate);

        if (transactionType != TransactionType.None)
        {
            // 获取所有相关分类（用于趋势图表）
            var allClassifies = budgets
                .SelectMany(b => b.SelectedCategories)
                .Distinct()
                .ToList();
            logger.LogDebug("相关分类数量: {ClassifyCount}", allClassifies.Count);

            // 获取趋势统计数据（仅用于图表展示）
            logger.LogDebug("开始获取交易趋势统计数据（用于图表）");
            var dailyStats = await transactionStatisticsService.GetFilteredTrendStatisticsAsync(
                startDate,
                endDate,
                transactionType,
                allClassifies);
            logger.LogDebug("获取到 {DayCount} 天的交易数据", dailyStats.Count);

            // 计算累计值（用于趋势图）
            decimal accumulated = 0;
            var daysInMonth = DateTime.DaysInMonth(startDate.Year, startDate.Month);
            logger.LogDebug("本月天数: {DaysInMonth}", daysInMonth);
            
            for (var i = 1; i <= daysInMonth; i++)
            {
                var currentDate = new DateTime(startDate.Year, startDate.Month, i);
                if (currentDate.Date > now.Date)
                {
                    result.Trend.Add(null);
                    logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd} 为未来日期，趋势数据为 null", currentDate);
                    continue;
                }

                if (dailyStats.TryGetValue(currentDate.Date, out var amount))
                {
                    accumulated += amount;
                    logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 金额={Amount}, 累计={Accumulated}", 
                        currentDate, amount, accumulated);
                }
                else
                {
                    logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 无交易数据，累计={Accumulated}", 
                        currentDate, accumulated);
                }
                
                // 对每一天的累计值应用硬性预算调整
                var adjustedAccumulated = accumulated;
                if (transactionType == TransactionType.Expense)
                {
                    var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
                    
                    // 检查是否为当前月份
                    var isCurrentMonth = referenceDate.Year == now.Year && referenceDate.Month == now.Month;
                    if (isCurrentMonth && currentDate.Date <= now.Date)
                    {
                        // 关键：accumulated是所有预算的实际交易累计（不包含虚拟消耗）
                        // totalMandatoryVirtual是所有硬性预算的虚拟消耗
                        // 但如果硬性预算有实际交易，accumulated中已经包含了，会重复
                        // 所以需要：accumulated + (totalMandatoryVirtual - 硬性预算的实际交易部分)
                        
                        // 更简单的理解：
                        // - 如果某个硬性预算本月完全没有交易记录，它的虚拟值应该加到accumulated上
                        // - 如果某个硬性预算有部分交易记录，应该补齐到虚拟值
                        // - 实现：取 max(accumulated, totalMandatoryVirtual) 是不对的
                        // - 正确：accumulated + 硬性预算中没有实际交易的那部分的虚拟值
                        
                        // 由于无法精确区分，采用近似方案：
                        // 计算所有硬性预算的Current总和，这个值已经包含了虚拟消耗（在CalculateCurrentAmountAsync中处理）

                        // 计算非硬性预算的交易累计（这部分在accumulated中）
                        // 但accumulated是所有交易的累计，包括硬性预算的实际交易
                        
                        // 最终简化方案：
                        // dailyStats包含所有实际交易（包括硬性预算的实际交易）
                        // 对于没有实际交易的硬性预算，它们的虚拟消耗没有在dailyStats中
                        // 所以：adjustedAccumulated = accumulated + 没有实际交易的硬性预算的虚拟消耗
                        
                        // 实用方法：每个硬性预算，取 max(它在dailyStats中的累计, 虚拟值)
                        // 但我们无法从dailyStats中提取单个预算的数据
                        
                        // 终极简化：如果硬性预算的Current值等于虚拟值，说明没有实际交易
                        // 这种情况下，accumulated中不包含这部分，需要加上虚拟值
                        // 如果Current值大于虚拟值，说明有实际交易，accumulated中已包含，不需要调整
                        
                        decimal mandatoryAdjustment = 0;
                        foreach (var budget in mandatoryBudgets)
                        {
                            decimal dailyVirtual = 0;
                            if (budget.Type == BudgetPeriodType.Month)
                            {
                                dailyVirtual = budget.Limit * i / daysInMonth;
                            }
                            else if (budget.Type == BudgetPeriodType.Year)
                            {
                                var daysInYear = DateTime.IsLeapYear(referenceDate.Year) ? 366 : 365;
                                var dayOfYear = currentDate.DayOfYear;
                                dailyVirtual = budget.Limit * dayOfYear / daysInYear;
                            }
                            
                            // 如果budget.Current约等于整月的虚拟值，说明没有实际交易
                            // 但Current是整个月的，dailyVirtual是到当前天的
                            // 需要判断该预算是否有实际交易记录
                            // 简化：假设如果硬性预算的Current等于虚拟值（误差<1元），就没有实际交易
                            
                            var monthlyVirtual = budget.Type == BudgetPeriodType.Month 
                                ? budget.Limit * now.Day / daysInMonth
                                : budget.Limit * now.DayOfYear / (DateTime.IsLeapYear(now.Year) ? 366 : 365);
                            
                            if (Math.Abs(budget.Current - monthlyVirtual) < 1)
                            {
                                // 没有实际交易，需要添加虚拟消耗
                                mandatoryAdjustment += dailyVirtual;
                                logger.LogTrace("日期 {CurrentDate:yyyy-MM-dd}: 硬性预算 {BudgetName} 无实际交易，添加虚拟消耗 {Virtual}",
                                    currentDate, budget.Name, dailyVirtual);
                            }
                        }
                        
                        adjustedAccumulated += mandatoryAdjustment;
                    }
                }
                
                result.Trend.Add(adjustedAccumulated);
            }
            
            logger.LogDebug("趋势图数据计算完成（已应用硬性预算调整）");
        }
        else
        {
            // 对于非收入/支出分类，趋势图为空
            logger.LogDebug("非收入/支出分类，趋势图为空");
        }

        // 对于硬性预算，如果当前月份且实际值为0，需要按时间比例计算
        if (transactionType == TransactionType.Expense)
        {
            logger.LogDebug("开始应用硬性预算调整，共 {BudgetCount} 个支出预算", budgets.Count);
            var beforeAdjustment = totalCurrent;
            totalCurrent = ApplyMandatoryBudgetAdjustment(budgets, totalCurrent, referenceDate, BudgetPeriodType.Month);
            if (Math.Abs(beforeAdjustment - totalCurrent) > 0.01m)
            {
                logger.LogInformation("硬性预算调整完成: 调整前={BeforeAdjustment}, 调整后={AfterAdjustment}, 调整金额={AdjustmentAmount}",
                    beforeAdjustment, totalCurrent, totalCurrent - beforeAdjustment);
                logger.LogDebug("硬性预算调整算法: 当前月份={ReferenceDate:yyyy-MM}, 硬性预算按天数比例累加计算", referenceDate);
            }
            else
            {
                logger.LogDebug("硬性预算调整未改变值");
            }
        }

        result.Current = totalCurrent;
        logger.LogInformation("【最终确定值】月度实际支出: {TotalCurrent}元（已应用硬性预算调整）", totalCurrent);

        // 4. 计算使用率
        result.Rate = totalLimit > 0 ? result.Current / totalLimit * 100 : 0;
        logger.LogInformation("【使用率】{Current}元 ÷ {Limit}元 × 100% = {Rate:F2}%", result.Current, totalLimit, result.Rate);

        // 5. 生成预算明细汇总日志
        var budgetDetails = budgets.Select(b => 
        {
            var limit = CalculateBudgetLimit(b, BudgetPeriodType.Month, referenceDate);
            var prefix = b.IsArchive ? $"({b.ArchiveMonth}月归档)" : "";
            var suffix = b.IsMandatoryExpense ? "[硬性]" : "";
            return $"{b.Name}{prefix}{suffix}:{limit}元";
        });
        var budgetSummary = string.Join(" + ", budgetDetails);
        logger.LogInformation("【月度预算明细】{BudgetDetails} = {TotalLimit}元",
            budgetSummary, totalLimit);

        // 6. 生成 HTML 描述
        result.Description = GenerateMonthlyDescription(budgets, totalLimit, totalCurrent, referenceDate, category);

        logger.LogDebug("月度分类统计计算完成");
        return result;
    }

    private async Task<BudgetStatsDto> CalculateYearlyCategoryStatsAsync(BudgetCategory category, DateTime referenceDate)
    {
        logger.LogDebug("开始计算年度分类统计: Category={Category}, ReferenceDate={ReferenceDate:yyyy}", 
            category, referenceDate);

        var result = new BudgetStatsDto
        {
            PeriodType = BudgetPeriodType.Year,
            Rate = 0,
            Current = 0,
            Limit = 0,
            Count = 0
        };

        // 1. 获取所有预算（包含归档数据）
        logger.LogDebug("开始获取预算数据（包含归档）");
        var budgets = await GetAllBudgetsWithArchiveAsync(category, BudgetPeriodType.Year, referenceDate);
        logger.LogDebug("获取到 {BudgetCount} 个预算", budgets.Count);

        if (budgets.Count == 0)
        {
            logger.LogDebug("未找到相关预算，返回空结果");
            return result;
        }

        result.Count = budgets.Count;

        // 2. 计算限额总值（考虑不限额预算的特殊处理）
        logger.LogDebug("开始计算年度限额总值，共 {BudgetCount} 个预算", budgets.Count);
        decimal totalLimit = 0;
        var budgetIndex = 0;
        foreach (var budget in budgets)
        {
            budgetIndex++;
            var itemLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
            logger.LogInformation("年度预算 {BudgetIndex}/{BudgetCount}: {BudgetName} - 原始预算金额: {BudgetLimit}, 当前实际金额: {CurrentAmount}, 预算类型: {BudgetType}, 算法: {Algorithm}",
                budgetIndex, budgets.Count, budget.Name, budget.Limit, budget.Current,
                budget.Type == BudgetPeriodType.Month ? "月度预算" : "年度预算",
                budget.NoLimit ? "不限额预算" : budget.IsMandatoryExpense ? "硬性预算" : "普通预算");
            totalLimit += itemLimit;
        }
        result.Limit = totalLimit;
        logger.LogDebug("年度限额总值计算完成: {TotalLimit}", totalLimit);

        // 3. 计算当前实际值
        var transactionType = category switch
        {
            BudgetCategory.Expense => TransactionType.Expense,
            BudgetCategory.Income => TransactionType.Income,
            _ => TransactionType.None
        };
        logger.LogDebug("交易类型: {TransactionType}", transactionType);

        // 计算当前实际值，考虑硬性预算的特殊逻辑
        var totalCurrent = budgets.Sum(b => b.Current);
        logger.LogInformation("【实际值来源】累加各预算的实际值: {TotalCurrent}元（共{Count}个预算）", 
            totalCurrent, budgets.Count);

        var now = dateTimeProvider.Now;
        var (startDate, endDate) = GetStatPeriodRange(BudgetPeriodType.Year, referenceDate);
        logger.LogDebug("统计时间段: {StartDate:yyyy-MM-dd} 到 {EndDate:yyyy-MM-dd}", startDate, endDate);

        if (transactionType != TransactionType.None)
        {
            // 获取所有相关分类（用于趋势图表）
            var allClassifies = budgets
                .SelectMany(b => b.SelectedCategories)
                .Distinct()
                .ToList();
            logger.LogDebug("相关分类数量: {ClassifyCount}", allClassifies.Count);

            // 获取趋势统计数据（仅用于图表展示）
            logger.LogDebug("开始获取交易趋势统计数据（用于图表）");
            var dailyStats = await transactionStatisticsService.GetFilteredTrendStatisticsAsync(
                startDate,
                endDate,
                transactionType,
                allClassifies,
                true);
            logger.LogDebug("获取到 {MonthCount} 个月的交易数据", dailyStats.Count);

            // 计算累计值（用于趋势图）
            decimal accumulated = 0;
            for (var i = 1; i <= 12; i++)
            {
                var currentMonthDate = new DateTime(startDate.Year, i, 1);

                if (currentMonthDate.Year > now.Year || (currentMonthDate.Year == now.Year && i > now.Month))
                {
                    result.Trend.Add(null);
                    logger.LogTrace("月份 {Month:yyyy-MM} 为未来月份，趋势数据为 null", currentMonthDate);
                    continue;
                }

                if (dailyStats.TryGetValue(currentMonthDate, out var amount))
                {
                    accumulated += amount;
                    logger.LogTrace("月份 {Month:yyyy-MM}: 金额={Amount}, 累计={Accumulated}", 
                        currentMonthDate, amount, accumulated);
                }
                else
                {
                    logger.LogTrace("月份 {Month:yyyy-MM}: 无交易数据，累计={Accumulated}", 
                        currentMonthDate, accumulated);
                }
                
                // 对每个月的累计值应用硬性预算调整
                var adjustedAccumulated = accumulated;
                if (transactionType == TransactionType.Expense)
                {
                    var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
                    
                    // 检查是否为当前年份
                    var isCurrentYear = referenceDate.Year == now.Year;
                    if (isCurrentYear && currentMonthDate <= now)
                    {
                        decimal mandatoryAdjustment = 0;
                        foreach (var budget in mandatoryBudgets)
                        {
                            decimal monthlyVirtual = 0;
                            
                            if (budget.Type == BudgetPeriodType.Month)
                            {
                                // 月度硬性预算：如果该月已完成，累加整月；如果是当前月，按天数比例
                                if (i < now.Month)
                                {
                                    monthlyVirtual = budget.Limit * i;
                                }
                                else if (i == now.Month)
                                {
                                    var daysInMonth = DateTime.DaysInMonth(now.Year, now.Month);
                                    monthlyVirtual = budget.Limit * (i - 1) + (budget.Limit * now.Day / daysInMonth);
                                }
                            }
                            else if (budget.Type == BudgetPeriodType.Year)
                            {
                                var daysInYear = DateTime.IsLeapYear(referenceDate.Year) ? 366 : 365;
                                var lastDayOfMonth = new DateTime(currentMonthDate.Year, i, DateTime.DaysInMonth(currentMonthDate.Year, i));
                                var dayOfYear = i < now.Month ? lastDayOfMonth.DayOfYear : now.DayOfYear;
                                monthlyVirtual = budget.Limit * dayOfYear / daysInYear;
                            }
                            
                            // 判断该硬性预算是否有实际交易
                            var yearlyVirtual = budget.Type == BudgetPeriodType.Month 
                                ? budget.Limit * now.Month + (budget.Limit * now.Day / DateTime.DaysInMonth(now.Year, now.Month)) - budget.Limit
                                : budget.Limit * now.DayOfYear / (DateTime.IsLeapYear(now.Year) ? 366 : 365);
                            
                            if (Math.Abs(budget.Current - yearlyVirtual) < 1)
                            {
                                // 没有实际交易，需要添加虚拟消耗
                                mandatoryAdjustment += monthlyVirtual;
                                logger.LogTrace("月份 {Month:yyyy-MM}: 硬性预算 {BudgetName} 无实际交易，添加虚拟消耗 {Virtual}",
                                    currentMonthDate, budget.Name, monthlyVirtual);
                            }
                        }
                        
                        adjustedAccumulated += mandatoryAdjustment;
                    }
                }
                
                result.Trend.Add(adjustedAccumulated);
            }

            logger.LogDebug("趋势图数据计算完成（已应用硬性预算调整）");
        }
        else
        {
            // 对于非收入/支出分类，趋势图为空
            logger.LogDebug("非收入/支出分类，趋势图为空");
        }

        // 对于硬性预算，如果当前年份且实际值为0，需要按时间比例计算
        if (transactionType == TransactionType.Expense)
        {
            logger.LogDebug("开始应用年度硬性预算调整，共 {BudgetCount} 个支出预算", budgets.Count);
            var beforeAdjustment = totalCurrent;
            totalCurrent = ApplyMandatoryBudgetAdjustment(budgets, totalCurrent, referenceDate, BudgetPeriodType.Year);
            if (Math.Abs(beforeAdjustment - totalCurrent) > 0.01m)
            {
                logger.LogInformation("年度硬性预算调整完成: 调整前={BeforeAdjustment}, 调整后={AfterAdjustment}, 调整金额={AdjustmentAmount}",
                    beforeAdjustment, totalCurrent, totalCurrent - beforeAdjustment);
                logger.LogDebug("年度硬性预算调整算法: 当前年份={ReferenceDate:yyyy}, 硬性预算按天数比例累加计算", referenceDate);
            }
            else
            {
                logger.LogDebug("年度硬性预算调整未改变值");
            }
        }

        result.Current = totalCurrent;
        logger.LogInformation("【最终确定值】年度实际支出: {TotalCurrent}元（已应用硬性预算调整）", totalCurrent);

        // 4. 计算使用率
        result.Rate = totalLimit > 0 ? result.Current / totalLimit * 100 : 0;
        logger.LogInformation("【使用率】{Current}元 ÷ {Limit}元 × 100% = {Rate:F2}%", result.Current, totalLimit, result.Rate);

        // 5. 生成预算明细汇总日志
        var budgetDetails = budgets.Select(b => 
        {
            var limit = CalculateBudgetLimit(b, BudgetPeriodType.Year, referenceDate);
            var prefix = b.IsArchive ? "(归档)" : b.RemainingMonths > 0 ? $"(剩余{b.RemainingMonths}月)" : "";
            var suffix = b.IsMandatoryExpense ? "[硬性]" : "";
            return $"{b.Name}{prefix}{suffix}:{limit}元";
        });
        var budgetSummary = string.Join(" + ", budgetDetails);
        logger.LogInformation("【年度预算明细】{BudgetDetails} = {TotalLimit}元",
            budgetSummary, totalLimit);

        // 6. 生成 HTML 描述
        result.Description = GenerateYearlyDescription(budgets, totalLimit, totalCurrent, referenceDate, category);

        logger.LogDebug("年度分类统计计算完成");
        return result;
    }

    private async Task<List<BudgetStatsItem>> GetAllBudgetsWithArchiveAsync(
        BudgetCategory category,
        BudgetPeriodType statType,
        DateTime referenceDate)
    {
        logger.LogDebug("开始获取预算数据: Category={Category}, StatType={StatType}, ReferenceDate={ReferenceDate:yyyy-MM-dd}", 
            category, statType, referenceDate);

        var result = new List<BudgetStatsItem>();

        var year = referenceDate.Year;
        var month = referenceDate.Month;
        var now = dateTimeProvider.Now;

        // 对于年度统计，需要获取整年的归档数据和当前预算
        if (statType == BudgetPeriodType.Year)
        {
            logger.LogDebug("年度统计：开始获取整年的预算数据");
            
            // 获取当前有效的预算（用于当前月及未来月）
            var currentBudgets = await budgetRepository.GetAllAsync();
            var currentBudgetsDict = currentBudgets
                .Where(b => b.Category == category && ShouldIncludeBudget(b, statType))
                .ToDictionary(b => b.Id);
            logger.LogDebug("获取到 {Count} 个当前有效预算", currentBudgetsDict.Count);

            // 用于跟踪已处理的预算ID，避免重复
            var processedBudgetIds = new HashSet<long>();
            
            // 1. 处理历史归档月份（1月到当前月-1）
            if (referenceDate.Year == now.Year && now.Month > 1)
            {
                logger.LogDebug("开始处理历史归档月份: 1月到{Month}月", now.Month - 1);
                for (var m = 1; m < now.Month; m++)
                {
                    var archive = await budgetArchiveRepository.GetArchiveAsync(year, m);
                    if (archive != null)
                    {
                        logger.LogDebug("找到{Month}月归档数据，包含 {ItemCount} 个项目", m, archive.Content.Count());
                        foreach (var item in archive.Content)
                        {
                            if (item.Category == category && ShouldIncludeBudget(item, statType))
                            {
                                // 对于月度预算，每个月都添加一个归档项
                                if (item.Type == BudgetPeriodType.Month)
                                {
                                    result.Add(new BudgetStatsItem
                                    {
                                        Id = item.Id,
                                        Name = item.Name,
                                        Type = item.Type,
                                        Limit = item.Limit,
                                        Current = item.Actual,
                                        Category = item.Category,
                                        SelectedCategories = item.SelectedCategories,
                                        NoLimit = item.NoLimit,
                                        IsMandatoryExpense = item.IsMandatoryExpense,
                                        IsArchive = true,
                                        ArchiveMonth = m
                                    });
                                    logger.LogInformation("添加归档月度预算: {BudgetName} - {Month}月归档, 预算金额: {Limit}, 实际金额: {Actual}",
                                        item.Name, m, item.Limit, item.Actual);
                                }
                                // 对于年度预算，只添加一次
                                else if (item.Type == BudgetPeriodType.Year && processedBudgetIds.Add(item.Id))
                                {
                                    result.Add(new BudgetStatsItem
                                    {
                                        Id = item.Id,
                                        Name = item.Name,
                                        Type = item.Type,
                                        Limit = item.Limit,
                                        Current = item.Actual,
                                        Category = item.Category,
                                        SelectedCategories = item.SelectedCategories,
                                        NoLimit = item.NoLimit,
                                        IsMandatoryExpense = item.IsMandatoryExpense,
                                        IsArchive = true
                                    });
                                    logger.LogInformation("添加归档年度预算: {BudgetName} - 预算金额: {Limit}, 实际金额: {Actual}",
                                        item.Name, item.Limit, item.Actual);
                                }
                            }
                        }
                    }
                }
            }
            
            // 2. 处理当前月及未来月（使用当前预算）
            logger.LogDebug("开始处理当前及未来月份预算");
            foreach (var budget in currentBudgetsDict.Values)
            {
                // 对于年度预算，如果还没有从归档中添加，则添加
                if (budget.Type == BudgetPeriodType.Year && !processedBudgetIds.Contains(budget.Id))
                {
                    var currentAmount = await CalculateCurrentAmountAsync(budget, statType, referenceDate);
                    result.Add(new BudgetStatsItem
                    {
                        Id = budget.Id,
                        Name = budget.Name,
                        Type = budget.Type,
                        Limit = budget.Limit,
                        Current = currentAmount,
                        Category = budget.Category,
                        SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
                            ? []
                            : budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
                        NoLimit = budget.NoLimit,
                        IsMandatoryExpense = budget.IsMandatoryExpense,
                        IsArchive = false
                    });
                    logger.LogInformation("添加当前年度预算: {BudgetName} - 预算金额: {Limit}, 实际金额: {Current}",
                        budget.Name, budget.Limit, currentAmount);
                }
                // 对于月度预算，仅添加当前月的预算项
                else if (budget.Type == BudgetPeriodType.Month)
                {
                    // 只计算当前月的实际值
                    var currentAmount = await CalculateCurrentAmountAsync(budget, BudgetPeriodType.Month, referenceDate);
                    result.Add(new BudgetStatsItem
                    {
                        Id = budget.Id,
                        Name = budget.Name,
                        Type = budget.Type,
                        Limit = budget.Limit, // 月度预算的原始限额
                        Current = currentAmount, // 当前月的实际值
                        Category = budget.Category,
                        SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
                            ? []
                            : budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
                        NoLimit = budget.NoLimit,
                        IsMandatoryExpense = budget.IsMandatoryExpense,
                        IsArchive = false,
                        // 标记这是当前月的月度预算，用于年度限额计算
                        IsCurrentMonth = true
                    });
                    logger.LogInformation("添加当前月的月度预算: {BudgetName} - 月度限额: {Limit}, 当前月实际值: {Current}",
                        budget.Name, budget.Limit, currentAmount);

                    // 如果还有剩余月份（未来月份），再添加一项作为未来的预算占位
                    var remainingMonths = 12 - now.Month;
                    if (remainingMonths > 0)
                    {
                        result.Add(new BudgetStatsItem
                        {
                            Id = budget.Id,
                            Name = budget.Name,
                            Type = budget.Type,
                            Limit = budget.Limit, // 月度预算的原始限额（用于描述时计算）
                            Current = 0, // 未来月份无实际值
                            Category = budget.Category,
                            SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
                                ? []
                                : budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
                            NoLimit = budget.NoLimit,
                            IsMandatoryExpense = budget.IsMandatoryExpense,
                            IsArchive = false,
                            IsCurrentMonth = false,
                            RemainingMonths = remainingMonths
                        });
                        logger.LogInformation("添加未来月份的月度预算: {BudgetName} - 月度限额: {Limit}, 剩余月份: {RemainingMonths}",
                            budget.Name, budget.Limit, remainingMonths);
                    }
                }
            }
        }
        else // 月度统计
        {
            // 检查是否为归档月份
            var isArchive = year < now.Year || (year == now.Year && month < now.Month);
            logger.LogDebug("月度统计 - 是否为归档月份: {IsArchive}", isArchive);

            if (isArchive)
            {
                // 获取归档数据
                logger.LogDebug("开始获取归档数据: Year={Year}, Month={Month}", year, month);
                var archive = await budgetArchiveRepository.GetArchiveAsync(year, month);
                
                if (archive != null)
                {
                    var itemCount = archive.Content.Count();
                    logger.LogDebug("找到归档数据，包含 {ItemCount} 个项目", itemCount);
                    foreach (var item in archive.Content)
                    {
                        if (item.Category == category && ShouldIncludeBudget(item, statType))
                        {
                            result.Add(new BudgetStatsItem
                            {
                                Id = item.Id,
                                Name = item.Name,
                                Type = item.Type,
                                Limit = item.Limit,
                                Current = item.Actual,
                                Category = item.Category,
                                SelectedCategories = item.SelectedCategories,
                                NoLimit = item.NoLimit,
                                IsMandatoryExpense = item.IsMandatoryExpense,
                                IsArchive = true
                            });
                            logger.LogInformation("添加归档预算: {BudgetName} - 归档月份: {Year}-{Month:00}, 预算金额: {BudgetLimit}, 实际金额: {ActualAmount}",
                                item.Name, year, month, item.Limit, item.Actual);
                        }
                    }
                }
                else
                {
                    logger.LogDebug("未找到归档数据");
                }
            }
            else
            {
                // 获取当前预算数据
                logger.LogDebug("开始获取当前预算数据");
                var budgets = await budgetRepository.GetAllAsync();
                var budgetCount = budgets.Count();
                logger.LogDebug("获取到 {BudgetCount} 个预算", budgetCount);
                
                foreach (var budget in budgets)
                {
                    if (budget.Category == category && ShouldIncludeBudget(budget, statType))
                    {
                        var currentAmount = await CalculateCurrentAmountAsync(budget, statType, referenceDate);
                        result.Add(new BudgetStatsItem
                        {
                            Id = budget.Id,
                            Name = budget.Name,
                            Type = budget.Type,
                            Limit = budget.Limit,
                            Current = currentAmount,
                            Category = budget.Category,
                            SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
                                ? []
                                : budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
                            NoLimit = budget.NoLimit,
                            IsMandatoryExpense = budget.IsMandatoryExpense,
                            IsArchive = false
                        });
                        logger.LogInformation("添加当前预算: {BudgetName} - 预算金额: {BudgetLimit}, 实时计算实际金额: {CurrentAmount}, 预算类型: {BudgetType}",
                            budget.Name, budget.Limit, currentAmount,
                            budget.Type == BudgetPeriodType.Month ? "月度预算" : "年度预算");
                    }
                }
            }
        }

        logger.LogDebug("预算数据获取完成: 共找到 {ResultCount} 个符合条件的预算", result.Count);
        return result;
    }

    private bool ShouldIncludeBudget(BudgetRecord budget, BudgetPeriodType statType)
    {
        // 排除不记额预算
        if (budget.NoLimit)
        {
            return false;
        }

        // 月度统计只包含月度预算
        if (statType == BudgetPeriodType.Month)
        {
            return budget.Type == BudgetPeriodType.Month;
        }

        // 年度统计包含所有预算
        return true;
    }

    private bool ShouldIncludeBudget(BudgetArchiveContent budget, BudgetPeriodType statType)
    {
        // 排除不记额预算
        if (budget.NoLimit)
        {
            return false;
        }

        // 月度统计只包含月度预算
        if (statType == BudgetPeriodType.Month)
        {
            return budget.Type == BudgetPeriodType.Month;
        }

        // 年度统计包含所有预算
        return true;
    }

    private decimal CalculateBudgetLimit(BudgetStatsItem budget, BudgetPeriodType statType, DateTime referenceDate)
    {
        // 不记额预算的限额为0
        if (budget.NoLimit)
        {
            logger.LogTrace("预算 {BudgetName} 为不记额预算，限额返回0", budget.Name);
            return 0;
        }

        var itemLimit = budget.Limit;
        var algorithmDescription = $"直接使用原始预算金额: {budget.Limit}";

        // 年度视图下，月度预算需要折算为年度
        if (statType == BudgetPeriodType.Year && budget.Type == BudgetPeriodType.Month)
        {
            // 对于归档预算，直接使用归档的限额，不折算
            if (budget.IsArchive)
            {
                itemLimit = budget.Limit;
                algorithmDescription = $"归档月度预算: 直接使用归档限额 {budget.Limit}";
            }
            // 对于当前月的月度预算，直接使用原始限额
            else if (budget.IsCurrentMonth)
            {
                itemLimit = budget.Limit;
                algorithmDescription = $"当前月的月度预算: 直接使用月度限额 {budget.Limit}";
            }
            // 对于当前及未来月份的预算，使用剩余月份折算
            else if (budget.RemainingMonths > 0)
            {
                itemLimit = budget.Limit * budget.RemainingMonths;
                algorithmDescription = $"月度预算剩余月份折算: {budget.Limit} × {budget.RemainingMonths} (剩余月份) = {itemLimit}";
            }
            // 兼容旧逻辑（如果没有设置RemainingMonths）
            else
            {
                logger.LogWarning("预算 {BudgetName} 年度统计时未设置RemainingMonths，使用默认折算逻辑", budget.Name);
                if (budget.IsMandatoryExpense)
                {
                    var now = dateTimeProvider.Now;
                    if (referenceDate.Year == now.Year)
                    {
                        var monthsElapsed = now.Month;
                        itemLimit = budget.Limit * monthsElapsed;
                        algorithmDescription = $"硬性预算当前年份折算: {budget.Limit} × {monthsElapsed} (已过月份) = {itemLimit}";
                    }
                    else
                    {
                        itemLimit = budget.Limit * 12;
                        algorithmDescription = $"硬性预算完整年度折算: {budget.Limit} × 12 = {itemLimit}";
                    }
                }
                else
                {
                    itemLimit = budget.Limit * 12;
                    algorithmDescription = $"月度预算年度折算: {budget.Limit} × 12 = {itemLimit}";
                }
            }
        }

        logger.LogInformation("预算 {BudgetName} 限额计算: 原始预算={OriginalLimit}, 计算后限额={CalculatedLimit}, 算法: {Algorithm}",
            budget.Name, budget.Limit, itemLimit, algorithmDescription);
        
        return itemLimit;
    }

    private async Task<decimal> CalculateCurrentAmountAsync(BudgetRecord budget, BudgetPeriodType statType, DateTime referenceDate)
    {
        var (startDate, endDate) = GetStatPeriodRange(statType, referenceDate);

        // 获取预算的实际时间段
        var (budgetStart, budgetEnd) = BudgetService.GetPeriodRange(budget.StartDate, budget.Type, referenceDate);

        // 确保在统计时间段内
        if (budgetEnd < startDate || budgetStart > endDate)
        {
            return 0;
        }

        var actualAmount = await budgetRepository.GetCurrentAmountAsync(budget, startDate, endDate);

        // 硬性预算的特殊处理（参考BudgetSavingsService第92-97行）
        if (actualAmount == 0 && budget.IsMandatoryExpense)
        {
            if (budget.Type == BudgetPeriodType.Month)
            {
                // 月度硬性预算按天数比例累加
                var daysInMonth = DateTime.DaysInMonth(referenceDate.Year, referenceDate.Month);
                var daysElapsed = dateTimeProvider.Now.Day;
                actualAmount = budget.Limit * daysElapsed / daysInMonth;
            }
            else if (budget.Type == BudgetPeriodType.Year)
            {
                // 年度硬性预算按天数比例累加
                var daysInYear = DateTime.IsLeapYear(referenceDate.Year) ? 366 : 365;
                var daysElapsed = dateTimeProvider.Now.DayOfYear;
                actualAmount = budget.Limit * daysElapsed / daysInYear;
            }
        }

        return actualAmount;
    }

    private decimal ApplyMandatoryBudgetAdjustment(List<BudgetStatsItem> budgets, decimal currentTotal, DateTime referenceDate, BudgetPeriodType statType)
    {
        logger.LogDebug("开始应用硬性预算调整: 当前总计={CurrentTotal}, 统计类型={StatType}, 参考日期={ReferenceDate:yyyy-MM-dd}", 
            currentTotal, statType, referenceDate);

        var now = dateTimeProvider.Now;
        var adjustedTotal = currentTotal;
        var mandatoryBudgets = budgets.Where(b => b.IsMandatoryExpense).ToList();
        
        logger.LogDebug("找到 {MandatoryCount} 个硬性预算", mandatoryBudgets.Count);

        var mandatoryIndex = 0;
        foreach (var budget in mandatoryBudgets)
        {
            mandatoryIndex++;
            // 检查是否为当前统计周期
            bool isCurrentPeriod;
            if (statType == BudgetPeriodType.Month)
            {
                isCurrentPeriod = referenceDate.Year == now.Year && referenceDate.Month == now.Month;
                logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查月度周期: 参考月份={RefMonth}, 当前月份={CurrentMonth}, 是否为当前周期={IsCurrent}", 
                    mandatoryIndex, mandatoryBudgets.Count, budget.Name, 
                    referenceDate.ToString("yyyy-MM"), now.ToString("yyyy-MM"), isCurrentPeriod);
            }
            else // Year
            {
                isCurrentPeriod = referenceDate.Year == now.Year;
                logger.LogInformation("硬性预算 {MandatoryIndex}/{MandatoryCount}: {BudgetName} - 检查年度周期: 参考年份={RefYear}, 当前年份={CurrentYear}, 是否为当前周期={IsCurrent}", 
                    mandatoryIndex, mandatoryBudgets.Count, budget.Name,
                    referenceDate.Year, now.Year, isCurrentPeriod);
            }

            if (isCurrentPeriod)
            {
                // 计算硬性预算的应累加值
                decimal mandatoryAccumulation = 0;
                var accumulationAlgorithm = "";
                
                if (budget.Type == BudgetPeriodType.Month)
                {
                    // 月度硬性预算按天数比例累加
                    var daysInMonth = DateTime.DaysInMonth(referenceDate.Year, referenceDate.Month);
                    var daysElapsed = now.Day;
                    mandatoryAccumulation = budget.Limit * daysElapsed / daysInMonth;
                    accumulationAlgorithm = $"月度硬性预算按天数比例: {budget.Limit} × {daysElapsed} ÷ {daysInMonth} = {mandatoryAccumulation:F2}";
                    logger.LogDebug("月度硬性预算 {BudgetName}: 限额={Limit}, 本月天数={DaysInMonth}, 已过天数={DaysElapsed}, 应累加值={Accumulation}", 
                        budget.Name, budget.Limit, daysInMonth, daysElapsed, mandatoryAccumulation);
                }
                else if (budget.Type == BudgetPeriodType.Year)
                {
                    // 年度硬性预算按天数比例累加
                    var daysInYear = DateTime.IsLeapYear(referenceDate.Year) ? 366 : 365;
                    var daysElapsed = now.DayOfYear;
                    mandatoryAccumulation = budget.Limit * daysElapsed / daysInYear;
                    accumulationAlgorithm = $"年度硬性预算按天数比例: {budget.Limit} × {daysElapsed} ÷ {daysInYear} = {mandatoryAccumulation:F2}";
                    logger.LogDebug("年度硬性预算 {BudgetName}: 限额={Limit}, 本年天数={DaysInYear}, 已过天数={DaysElapsed}, 应累加值={Accumulation}", 
                        budget.Name, budget.Limit, daysInYear, daysElapsed, mandatoryAccumulation);
                }

                logger.LogInformation("硬性预算 {BudgetName} 应累加值计算: 算法={Algorithm}",
                    budget.Name, accumulationAlgorithm);

                // 如果趋势数据中的累计值小于硬性预算的应累加值，使用硬性预算的值
                if (adjustedTotal < mandatoryAccumulation)
                {
                    var adjustmentAmount = mandatoryAccumulation - adjustedTotal;
                    logger.LogInformation("硬性预算 {BudgetName} 触发调整: 调整前总计={BeforeTotal}, 应累加值={MandatoryAccumulation}, 调整金额={AdjustmentAmount}, 调整后总计={AfterTotal}",
                        budget.Name, adjustedTotal, mandatoryAccumulation, adjustmentAmount, mandatoryAccumulation);
                    adjustedTotal = mandatoryAccumulation;
                }
                else
                {
                    logger.LogDebug("硬性预算 {BudgetName} 未触发调整: 当前总计={CurrentTotal} >= 应累加值={MandatoryAccumulation}", 
                        budget.Name, adjustedTotal, mandatoryAccumulation);
                }
            }
            else
            {
                logger.LogInformation("硬性预算 {BudgetName} 不在当前统计周期，跳过调整", budget.Name);
            }
        }

        logger.LogDebug("硬性预算调整完成: 最终总计={AdjustedTotal}", adjustedTotal);
        return adjustedTotal;
    }

    private (DateTime start, DateTime end) GetStatPeriodRange(BudgetPeriodType statType, DateTime referenceDate)
    {
        if (statType == BudgetPeriodType.Month)
        {
            var start = new DateTime(referenceDate.Year, referenceDate.Month, 1);
            var end = start.AddMonths(1).AddDays(-1).AddHours(23).AddMinutes(59).AddSeconds(59);
            return (start, end);
        }
        else // Year
        {
            var start = new DateTime(referenceDate.Year, 1, 1);
            var end = new DateTime(referenceDate.Year, 12, 31).AddHours(23).AddMinutes(59).AddSeconds(59);
            return (start, end);
        }
    }

    private record BudgetStatsItem
    {
        public long Id { get; init; }
        public string Name { get; init; } = string.Empty;
        public BudgetPeriodType Type { get; init; }
        public decimal Limit { get; init; }
        public decimal Current { get; init; }
        public BudgetCategory Category { get; set; }
        public string[] SelectedCategories { get; init; } = [];
        public bool NoLimit { get; init; }
        public bool IsMandatoryExpense { get; init; }
        public bool IsArchive { get; init; }
        public int ArchiveMonth { get; init; } // 归档月份（1-12），用于标识归档数据来自哪个月
        public int RemainingMonths { get; init; } // 剩余月份数，用于年度统计时的月度预算折算
        public bool IsCurrentMonth { get; init; } // 标记是否为当前月的预算（用于年度统计中月度预算的计算）
    }

    private string GenerateMonthlyDescription(List<BudgetStatsItem> budgets, decimal totalLimit, decimal totalCurrent, DateTime referenceDate, BudgetCategory category)
    {
        var description = new StringBuilder();
        var categoryName = category == BudgetCategory.Expense ? "支出" : "收入";

        description.AppendLine($"<h3>月度{categoryName}预算明细</h3>");
        description.AppendLine("""
        <table>
            <thead>
                <tr>
                    <th>名称</th>
                    <th>预算额度</th>
                    <th>实际金额</th>
                    <th>类型</th>
                </tr>
            </thead>
            <tbody>
        """);

        foreach (var budget in budgets)
        {
            var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Month, referenceDate);
            var typeLabel = budget.IsMandatoryExpense ? "硬性" : "普通";
            var archiveLabel = budget.IsArchive ? $" ({budget.ArchiveMonth}月归档)" : "";
            
            description.AppendLine($"""
            <tr>
                <td>{budget.Name}{archiveLabel}</td>
                <td>{budgetLimit:N0}</td>
                <td><span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'>{budget.Current:N1}</span></td>
                <td>{typeLabel}</td>
            </tr>
            """);
        }

        description.AppendLine("</tbody></table>");

        // 计算公式
        description.AppendLine($"<h3>计算公式</h3>");
        description.AppendLine($"<p><strong>预算额度合计：</strong>");
        var limitParts = budgets.Select(b =>
        {
            var limit = CalculateBudgetLimit(b, BudgetPeriodType.Month, referenceDate);
            var archiveLabel = b.IsArchive ? $"({b.ArchiveMonth}月归档)" : "";
            return $"{b.Name}{archiveLabel}({limit:N0})";
        });
        description.AppendLine($"{string.Join(" + ", limitParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalLimit:N0}</strong></span></p>");

        description.AppendLine($"<p><strong>实际{categoryName}合计：</strong>");
        var currentParts = budgets.Select(b =>
        {
            var archiveLabel = b.IsArchive ? $"({b.ArchiveMonth}月归档)" : "";
            return $"{b.Name}{archiveLabel}({b.Current:N1})";
        });
        description.AppendLine($"{string.Join(" + ", currentParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalCurrent:N1}</strong></span></p>");

        var rate = totalLimit > 0 ? totalCurrent / totalLimit * 100 : 0;
        description.AppendLine($"<p><strong>使用率：</strong>{totalCurrent:N1} ÷ {totalLimit:N0} × 100% = <span class='highlight'><strong>{rate:F2}%</strong></span></p>");

        return description.ToString();
    }

    private string GenerateYearlyDescription(List<BudgetStatsItem> budgets, decimal totalLimit, decimal totalCurrent, DateTime referenceDate, BudgetCategory category)
    {
        var description = new StringBuilder();
        var categoryName = category == BudgetCategory.Expense ? "支出" : "收入";

        // 分组：归档的月度预算、归档的年度预算、当前月度预算（剩余月份）、当前年度预算
        var archivedMonthlyBudgets = budgets.Where(b => b is { IsArchive: true, Type: BudgetPeriodType.Month }).ToList();
        var archivedYearlyBudgets = budgets.Where(b => b is { IsArchive: true, Type: BudgetPeriodType.Year }).ToList();
        var currentMonthlyBudgets = budgets.Where(b => b is { IsArchive: false, Type: BudgetPeriodType.Month }).ToList();
        var currentYearlyBudgets = budgets.Where(b => b is { IsArchive: false, Type: BudgetPeriodType.Year }).ToList();

        // 归档月度预算明细
        if (archivedMonthlyBudgets.Any())
        {
            description.AppendLine($"<h3>已归档月度{categoryName}预算</h3>");
            description.AppendLine("""
            <table>
                <thead>
                    <tr>
                        <th>名称</th>
                        <th>预算额度</th>
                        <th>实际金额</th>
                        <th>归档月份</th>
                    </tr>
                </thead>
                <tbody>
            """);

            foreach (var budget in archivedMonthlyBudgets.GroupBy(b => b.Id))
            {
                var first = budget.First();
                var months = budget.Select(b => b.ArchiveMonth).OrderBy(m => m).ToArray();
                var monthsText = FormatMonths(months);
                var groupLimit = first.Limit * budget.Count();
                var groupCurrent = budget.Sum(b => b.Current);

                description.AppendLine($"""
                <tr>
                    <td>{first.Name}</td>
                    <td>{groupLimit:N0}</td>
                    <td><span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'>{groupCurrent:N1}</span></td>
                    <td>{monthsText}</td>
                </tr>
                """);
            }

            description.AppendLine("</tbody></table>");
        }

        // 当前月度预算（剩余月份）
        if (currentMonthlyBudgets.Any())
        {
            description.AppendLine($"<h3>当前月度{categoryName}预算（当前月及未来月）</h3>");
            description.AppendLine("""
            <table>
                <thead>
                    <tr>
                        <th>名称</th>
                        <th>类型</th>
                        <th>计算方式</th>
                        <th>合计额度</th>
                        <th>实际金额</th>
                    </tr>
                </thead>
                <tbody>
            """);

            foreach (var budget in currentMonthlyBudgets)
            {
                var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
                var typeStr = budget.IsCurrentMonth ? "当前月" : "未来月";
                var calcStr = budget.IsCurrentMonth 
                    ? $"1月×{budget.Limit:N0}" 
                    : $"{budget.RemainingMonths}月×{budget.Limit:N0}";

                description.AppendLine($"""
                <tr>
                    <td>{budget.Name}</td>
                    <td>{typeStr}</td>
                    <td>{calcStr}</td>
                    <td>{budgetLimit:N0}</td>
                    <td>{(budget.IsCurrentMonth ? budget.Current.ToString("N1") : "-")}</td>
                </tr>
                """);
            }

            description.AppendLine("</tbody></table>");
        }

        // 年度预算明细
        if (archivedYearlyBudgets.Any() || currentYearlyBudgets.Any())
        {
            description.AppendLine($"<h3>年度{categoryName}预算</h3>");
            description.AppendLine("""
            <table>
                <thead>
                    <tr>
                        <th>名称</th>
                        <th>预算额度</th>
                        <th>实际金额</th>
                        <th>状态</th>
                    </tr>
                </thead>
                <tbody>
            """);

            foreach (var budget in archivedYearlyBudgets.Concat(currentYearlyBudgets))
            {
                var statusLabel = budget.IsArchive ? "归档" : "当前";
                var typeLabel = budget.IsMandatoryExpense ? "硬性" : "普通";

                description.AppendLine($"""
                <tr>
                    <td>{budget.Name}</td>
                    <td>{budget.Limit:N0}</td>
                    <td><span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'>{budget.Current:N1}</span></td>
                    <td>{statusLabel}/{typeLabel}</td>
                </tr>
                """);
            }

            description.AppendLine("</tbody></table>");
        }

        // 计算公式
        description.AppendLine($"<h3>计算公式</h3>");
        description.AppendLine($"<p><strong>年度预算额度合计：</strong>");
        var limitParts = new List<string>();
        
        // 归档月度预算部分
        foreach (var group in archivedMonthlyBudgets.GroupBy(b => b.Id))
        {
            var first = group.First();
            var count = group.Count();
            var groupTotalLimit = first.Limit * count;
            limitParts.Add($"{first.Name}(归档{count}月×{first.Limit:N0}={groupTotalLimit:N0})");
        }
        
        // 当前月度预算部分
        foreach (var budget in currentMonthlyBudgets)
        {
            var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
            if (budget.IsCurrentMonth)
            {
                limitParts.Add($"{budget.Name}(当前月×{budget.Limit:N0}={budgetLimit:N0})");
            }
            else
            {
                limitParts.Add($"{budget.Name}(剩余{budget.RemainingMonths}月×{budget.Limit:N0}={budgetLimit:N0})");
            }
        }
        
        // 年度预算部分
        foreach (var budget in archivedYearlyBudgets.Concat(currentYearlyBudgets))
        {
            limitParts.Add($"{budget.Name}({budget.Limit:N0})");
        }
        
        description.AppendLine($"{string.Join(" + ", limitParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalLimit:N0}</strong></span></p>");

        description.AppendLine($"<p><strong>实际{categoryName}合计：</strong>");
        var currentParts = new List<string>();
        
        // 归档月度预算的实际值
        foreach (var group in archivedMonthlyBudgets.GroupBy(b => b.Id))
        {
            var first = group.First();
            var groupTotalCurrent = group.Sum(b => b.Current);
            currentParts.Add($"{first.Name}(归档{groupTotalCurrent:N1})");
        }
        
        // 年度预算的实际值
        foreach (var budget in archivedYearlyBudgets.Concat(currentYearlyBudgets))
        {
            currentParts.Add($"{budget.Name}({budget.Current:N1})");
        }
        
        description.AppendLine($"{string.Join(" + ", currentParts)} = <span class='{(category == BudgetCategory.Expense ? "expense-value" : "income-value")}'><strong>{totalCurrent:N1}</strong></span></p>");

        var rate = totalLimit > 0 ? totalCurrent / totalLimit * 100 : 0;
        description.AppendLine($"<p><strong>使用率：</strong>{totalCurrent:N1} ÷ {totalLimit:N0} × 100% = <span class='highlight'><strong>{rate:F2}%</strong></span></p>");

        return description.ToString();
    }

    private string FormatMonths(int[] months)
    {
        if (months.Length == 0) return "";
        if (months.Length == 1) return $"{months[0]}月";

        // 如果是连续的月份，简化显示为 1~3月
        Array.Sort(months);
        var isContinuous = true;
        for (var i = 1; i < months.Length; i++)
        {
            if (months[i] != months[i - 1] + 1)
            {
                isContinuous = false;
                break;
            }
        }

        if (isContinuous)
        {
            return $"{months.First()}~{months.Last()}月";
        }

        return string.Join(", ", months) + "月";
    }
}