namespace WebApi.Controllers;

[ApiController]
[Route("api/[controller]/[action]")]
public class BudgetController(
    IBudgetService budgetService,
    IConfigService configService,
    ILogger<BudgetController> logger) : ControllerBase
{
    /// <summary>
    /// 获取预算列表
    /// </summary>
    [HttpGet]
    public async Task<BaseResponse<List<BudgetDto>>> GetListAsync([FromQuery] DateTime? referenceDate = null)
    {
        try
        {
            var budgets = await budgetService.GetAllAsync();
            var dtos = new List<BudgetDto?>();

            foreach (var budget in budgets)
            {
                var currentAmount = await budgetService.CalculateCurrentAmountAsync(budget, referenceDate);
                dtos.Add(BudgetDto.FromEntity(budget, currentAmount, referenceDate));
            }

            // 创造虚拟的存款预算
            dtos.Add(await GetVirtualSavingsDtoAsync(
                BudgetPeriodType.Month, 
                referenceDate,
                budgets));
            dtos.Add(await GetVirtualSavingsDtoAsync(
                BudgetPeriodType.Year, 
                referenceDate,
                budgets));

            return dtos.Where(dto => dto != null).Cast<BudgetDto>().ToList().Ok();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "获取预算列表失败");
            return $"获取预算列表失败: {ex.Message}".Fail<List<BudgetDto>>();
        }
    }

    /// <summary>
    /// 获取单个预算统计信息
    /// </summary>
    [HttpGet]
    public async Task<BaseResponse<BudgetDto>> GetStatisticsAsync([FromQuery] long id, [FromQuery] DateTime? referenceDate = null)
    {
        try
        {
            if (id == -1)
            {
                return (await GetVirtualSavingsDtoAsync(BudgetPeriodType.Year, referenceDate))!.Ok();
            }
            if (id == -2)
            {
                return (await GetVirtualSavingsDtoAsync(BudgetPeriodType.Month, referenceDate))!.Ok();
            }

            var budget = await budgetService.GetByIdAsync(id);
            if (budget == null) return "预算不存在".Fail<BudgetDto>();

            var currentAmount = await budgetService.CalculateCurrentAmountAsync(budget, referenceDate);
            return BudgetDto.FromEntity(budget, currentAmount, referenceDate).Ok();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "获取预算统计失败, Id: {Id}", id);
            return $"获取预算统计失败: {ex.Message}".Fail<BudgetDto>();
        }
    }

    /// <summary>
    /// 删除预算
    /// </summary>
    [HttpDelete("{id}")]
    public async Task<BaseResponse> DeleteByIdAsync(long id)
    {
        try
        {
            var success = await budgetService.DeleteAsync(id);
            return success ? BaseResponse.Done() : "删除预算失败".Fail();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "删除预算失败, Id: {Id}", id);
            return $"删除预算失败: {ex.Message}".Fail();
        }
    }

    /// <summary>
    /// 创建预算
    /// </summary>
    [HttpPost]
    public async Task<BaseResponse<long>> CreateAsync([FromBody] CreateBudgetDto dto)
    {
        try
        {
            var budget = new BudgetRecord
            {
                Name = dto.Name,
                Type = dto.Type,
                Limit = dto.Limit,
                Category = dto.Category,
                SelectedCategories = dto.SelectedCategories != null ? string.Join(",", dto.SelectedCategories) : string.Empty,
                StartDate = dto.StartDate ?? DateTime.Now
            };

            var varidationError = await ValidateBudgetSelectedCategoriesAsync(budget);
            if (!string.IsNullOrEmpty(varidationError))
            {
                return varidationError.Fail<long>();
            }

            var success = await budgetService.AddAsync(budget);
            if (success)
            {
                return budget.Id.Ok();
            }
            return "创建预算失败".Fail<long>();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "创建预算失败");
            return $"创建预算失败: {ex.Message}".Fail<long>();
        }
    }

    /// <summary>
    /// 更新预算
    /// </summary>
    [HttpPost]
    public async Task<BaseResponse> UpdateAsync([FromBody] UpdateBudgetDto dto)
    {
        try
        {
            var budget = await budgetService.GetByIdAsync(dto.Id);
            if (budget == null) return "预算不存在".Fail();

            budget.Name = dto.Name;
            budget.Type = dto.Type;
            budget.Limit = dto.Limit;
            budget.Category = dto.Category;
            budget.SelectedCategories = dto.SelectedCategories != null ? string.Join(",", dto.SelectedCategories) : string.Empty;
            budget.IsStopped = dto.IsStopped;
            if (dto.StartDate.HasValue)
            {
                budget.StartDate = dto.StartDate.Value;
            }

            var varidationError = await ValidateBudgetSelectedCategoriesAsync(budget);
            if (!string.IsNullOrEmpty(varidationError))
            {
                return varidationError.Fail();
            }

            var success = await budgetService.UpdateAsync(budget);
            return success ? BaseResponse.Done() : "更新预算失败".Fail();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "更新预算失败, Id: {Id}", dto.Id);
            return $"更新预算失败: {ex.Message}".Fail();
        }
    }

    private async Task<BudgetDto?> GetVirtualSavingsDtoAsync(
        BudgetPeriodType periodType, 
        DateTime? referenceDate = null,
        List<BudgetRecord>? existingBudgets = null)
    {
        var allBudgets = existingBudgets;

        if(existingBudgets == null)
        {
            allBudgets = await budgetService.GetAllAsync();
        }

        if(allBudgets == null)
        {
            return null;
        }

        var date = referenceDate ?? DateTime.Now;

        decimal incomeLimitAtPeriod = 0;
        decimal expenseLimitAtPeriod = 0;
        
        var incomeItems = new List<(string Name, decimal Limit, decimal Factor, decimal Total)>();
        var expenseItems = new List<(string Name, decimal Limit, decimal Factor, decimal Total)>();

        foreach (var b in allBudgets)
        {
            if (b.IsStopped || b.Category == BudgetCategory.Savings) continue;

            // 折算系数：根据当前请求的 periodType (Year 或 Month)，将预算 b 的 Limit 折算过来
            decimal factor = 1.0m;

            if (periodType == BudgetPeriodType.Year)
            {
                factor = b.Type switch
                {
                    BudgetPeriodType.Month => 12,
                    BudgetPeriodType.Year => 1,
                    _ => 0
                };
            }
            else if (periodType == BudgetPeriodType.Month)
            {
                factor = b.Type switch
                {
                    BudgetPeriodType.Month => 1,
                    BudgetPeriodType.Year => 0,
                    _ => 0
                };
            }
            else
            {
                factor = 0; // 其他周期暂不计算虚拟存款
            }

            if (factor <= 0) continue;

            var subtotal = b.Limit * factor;
            if (b.Category == BudgetCategory.Income)
            {
                incomeLimitAtPeriod += subtotal;
                incomeItems.Add((b.Name, b.Limit, factor, subtotal));
            }
            else if (b.Category == BudgetCategory.Expense)
            {
                expenseLimitAtPeriod += subtotal;
                expenseItems.Add((b.Name, b.Limit, factor, subtotal));
            }
        }

        var description = new StringBuilder();
        description.Append("<h3>预算收入明细</h3>");
        if (incomeItems.Count == 0) description.Append("<p>无收入预算</p>");
        else
        {
            description.Append("<table><thead><tr><th>名称</th><th>金额</th><th>折算</th><th>合计</th></tr></thead><tbody>");
            foreach (var item in incomeItems)
            {
                description.Append($"<tr><td>{item.Name}</td><td>{item.Limit:N0}</td><td>x{item.Factor:0.##}</td><td><span class='income-value'>{item.Total:N0}</span></td></tr>");
            }
            description.Append("</tbody></table>");
        }
        description.Append($"<p>收入合计: <span class='income-value'><strong>{incomeLimitAtPeriod:N0}</strong></span></p>");

        description.Append("<h3>预算支出明细</h3>");
        if (expenseItems.Count == 0) description.Append("<p>无支出预算</p>");
        else
        {
            description.Append("<table><thead><tr><th>名称</th><th>金额</th><th>折算</th><th>合计</th></tr></thead><tbody>");
            foreach (var item in expenseItems)
            {
                description.Append($"<tr><td>{item.Name}</td><td>{item.Limit:N0}</td><td>x{item.Factor:0.##}</td><td><span class='expense-value'>{item.Total:N0}</span></td></tr>");
            }
            description.Append("</tbody></table>");
        }
        description.Append($"<p>支出合计: <span class='expense-value'><strong>{expenseLimitAtPeriod:N0}</strong></span></p>");

        description.Append("<h3>存款计划结论</h3>");
        description.Append($"<p>计划存款 = 收入 <span class='income-value'>{incomeLimitAtPeriod:N0}</span> - 支出 <span class='expense-value'>{expenseLimitAtPeriod:N0}</span></p>");
        description.Append($"<p>最终目标：<span class='highlight'><strong>{incomeLimitAtPeriod - expenseLimitAtPeriod:N0}</strong></span></p>");

        var savingsCategories = await configService.GetConfigByKeyAsync<string>("SavingsCategories") ?? string.Empty;
        var virtualBudget = new BudgetRecord
        {
            Id = periodType == BudgetPeriodType.Year ? -1 : -2,
            Name = periodType == BudgetPeriodType.Year ? "年度存款" : "月度存款",
            Category = BudgetCategory.Savings,
            Type = periodType,
            Limit = incomeLimitAtPeriod - expenseLimitAtPeriod,
            StartDate = periodType == BudgetPeriodType.Year ? new DateTime(date.Year, 1, 1) : new DateTime(date.Year, date.Month, 1),
            SelectedCategories = savingsCategories
        };

        // 计算实际发生的 收入 - 支出
        var incomeHelper = new BudgetRecord { Category = BudgetCategory.Income, Type = periodType, StartDate = virtualBudget.StartDate, SelectedCategories = savingsCategories };
        var expenseHelper = new BudgetRecord { Category = BudgetCategory.Expense, Type = periodType, StartDate = virtualBudget.StartDate, SelectedCategories = savingsCategories };

        var actualIncome = await budgetService.CalculateCurrentAmountAsync(incomeHelper, date);
        var actualExpense = await budgetService.CalculateCurrentAmountAsync(expenseHelper, date);

        return BudgetDto.FromEntity(virtualBudget, actualIncome - actualExpense, date, description.ToString());
    }

    private async Task<string> ValidateBudgetSelectedCategoriesAsync(BudgetRecord record)
    {
        var allBudgets = await budgetService.GetAllAsync();

        var recordSelectedCategories = record.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries);
        foreach (var budget in allBudgets)
        {
            var selectedCategories = budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries);
            if (budget.Id != record.Id)
            {
                if (budget.Category == record.Category &&
                    recordSelectedCategories.Intersect(selectedCategories).Any())
                {
                    return $"和 {budget.Name} 存在分类冲突，请调整相关分类。";
                }
            }
        }

        return string.Empty;
    }

    /// <summary>
    /// 切换预算暂停状态
    /// </summary>
    [HttpPost]
    public async Task<BaseResponse> ToggleStopAsync([FromQuery] long id)
    {
        try
        {
            var success = await budgetService.ToggleStopAsync(id);
            return success ? BaseResponse.Done() : "操作失败".Fail();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "切换预算状态失败, Id: {Id}", id);
            return $"操作失败: {ex.Message}".Fail();
        }
    }

}
