using System.Globalization;
using TakeoutSaaS.Application.App.Finance.Cost.Dto;
using TakeoutSaaS.Domain.Finance.Enums;
using TakeoutSaaS.Domain.Finance.Models;

namespace TakeoutSaaS.Application.App.Finance.Cost.Handlers;

/// <summary>
/// 成本模块映射与文案转换。
/// </summary>
internal static class FinanceCostMapping
{
    /// <summary>
    /// 维度编码转枚举。
    /// </summary>
    public static FinanceCostDimension ParseDimensionCode(string? value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "store" => FinanceCostDimension.Store,
            _ => FinanceCostDimension.Tenant
        };
    }

    /// <summary>
    /// 维度枚举转编码。
    /// </summary>
    public static string ToDimensionCode(FinanceCostDimension value)
    {
        return value == FinanceCostDimension.Store ? "store" : "tenant";
    }

    /// <summary>
    /// 分类编码转枚举。
    /// </summary>
    public static FinanceCostCategory ParseCategoryCode(string? value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "food" => FinanceCostCategory.FoodMaterial,
            "labor" => FinanceCostCategory.Labor,
            "fixed" => FinanceCostCategory.FixedExpense,
            "packaging" => FinanceCostCategory.PackagingConsumable,
            _ => FinanceCostCategory.FoodMaterial
        };
    }

    /// <summary>
    /// 分类枚举转编码。
    /// </summary>
    public static string ToCategoryCode(FinanceCostCategory value)
    {
        return value switch
        {
            FinanceCostCategory.FoodMaterial => "food",
            FinanceCostCategory.Labor => "labor",
            FinanceCostCategory.FixedExpense => "fixed",
            FinanceCostCategory.PackagingConsumable => "packaging",
            _ => "food"
        };
    }

    /// <summary>
    /// 分类文案。
    /// </summary>
    public static string ToCategoryText(FinanceCostCategory value)
    {
        return value switch
        {
            FinanceCostCategory.FoodMaterial => "食材原料",
            FinanceCostCategory.Labor => "人工成本",
            FinanceCostCategory.FixedExpense => "固定费用",
            FinanceCostCategory.PackagingConsumable => "包装耗材",
            _ => "食材原料"
        };
    }

    /// <summary>
    /// 格式化月份字符串（yyyy-MM）。
    /// </summary>
    public static string ToMonthText(DateTime month)
    {
        return month.ToString("yyyy-MM", CultureInfo.InvariantCulture);
    }

    /// <summary>
    /// 归一化金额精度。
    /// </summary>
    public static decimal RoundAmount(decimal value)
    {
        return decimal.Round(value, 2, MidpointRounding.AwayFromZero);
    }

    /// <summary>
    /// 构建录入页 DTO。
    /// </summary>
    public static FinanceCostEntryDto ToEntryDto(FinanceCostMonthSnapshot snapshot)
    {
        // 1. 计算总成本与成本率。
        var totalCost = RoundAmount(snapshot.Categories.Sum(item => item.TotalAmount));
        var costRate = snapshot.MonthRevenue > 0
            ? RoundAmount(totalCost / snapshot.MonthRevenue * 100m)
            : 0m;

        // 2. 映射分类与明细。
        var categories = snapshot.Categories.Select(category =>
        {
            var percentage = totalCost > 0
                ? RoundAmount(category.TotalAmount / totalCost * 100m)
                : 0m;

            return new FinanceCostEntryCategoryDto
            {
                Category = ToCategoryCode(category.Category),
                CategoryText = ToCategoryText(category.Category),
                TotalAmount = RoundAmount(category.TotalAmount),
                Percentage = percentage,
                Items = category.Items
                    .OrderBy(item => item.SortOrder)
                    .ThenBy(item => item.ItemName)
                    .Select(item => new FinanceCostEntryDetailDto
                    {
                        ItemId = item.ItemId?.ToString(CultureInfo.InvariantCulture),
                        ItemName = item.ItemName,
                        Amount = RoundAmount(item.Amount),
                        Quantity = item.Quantity.HasValue ? RoundAmount(item.Quantity.Value) : null,
                        UnitPrice = item.UnitPrice.HasValue ? RoundAmount(item.UnitPrice.Value) : null,
                        SortOrder = item.SortOrder
                    })
                    .ToList()
            };
        }).ToList();

        return new FinanceCostEntryDto
        {
            Dimension = ToDimensionCode(snapshot.Dimension),
            StoreId = snapshot.StoreId?.ToString(CultureInfo.InvariantCulture),
            Month = ToMonthText(snapshot.CostMonth),
            MonthRevenue = RoundAmount(snapshot.MonthRevenue),
            TotalCost = totalCost,
            CostRate = costRate,
            Categories = categories
        };
    }

    /// <summary>
    /// 构建分析页 DTO。
    /// </summary>
    public static FinanceCostAnalysisDto ToAnalysisDto(FinanceCostAnalysisSnapshot snapshot)
    {
        // 1. 计算统计指标。
        var averageCostPerPaidOrder = snapshot.CurrentPaidOrderCount > 0
            ? RoundAmount(snapshot.CurrentTotalCost / snapshot.CurrentPaidOrderCount)
            : 0m;
        var foodCostRate = snapshot.CurrentRevenue > 0
            ? RoundAmount(snapshot.CurrentFoodAmount / snapshot.CurrentRevenue * 100m)
            : 0m;

        // 2. 映射趋势与明细表。
        var trend = snapshot.Trends
            .OrderBy(item => item.MonthStartUtc)
            .Select(item =>
            {
                var costRate = item.Revenue > 0
                    ? RoundAmount(item.TotalCost / item.Revenue * 100m)
                    : 0m;

                return new FinanceCostTrendPointDto
                {
                    Month = ToMonthText(item.MonthStartUtc),
                    TotalCost = RoundAmount(item.TotalCost),
                    Revenue = RoundAmount(item.Revenue),
                    CostRate = costRate
                };
            })
            .ToList();

        var detailRows = snapshot.DetailRows
            .OrderByDescending(item => item.MonthStartUtc)
            .Select(item =>
            {
                var costRate = item.Revenue > 0
                    ? RoundAmount(item.TotalCost / item.Revenue * 100m)
                    : 0m;

                return new FinanceCostMonthlyDetailRowDto
                {
                    Month = ToMonthText(item.MonthStartUtc),
                    FoodAmount = RoundAmount(item.FoodAmount),
                    LaborAmount = RoundAmount(item.LaborAmount),
                    FixedAmount = RoundAmount(item.FixedAmount),
                    PackagingAmount = RoundAmount(item.PackagingAmount),
                    TotalCost = RoundAmount(item.TotalCost),
                    CostRate = costRate
                };
            })
            .ToList();

        // 3. 构建成本构成。
        var totalCost = RoundAmount(snapshot.CurrentTotalCost);
        var composition = snapshot.CurrentCategories
            .OrderBy(item => item.Category)
            .Select(item => new FinanceCostCompositionItemDto
            {
                Category = ToCategoryCode(item.Category),
                CategoryText = ToCategoryText(item.Category),
                Amount = RoundAmount(item.TotalAmount),
                Percentage = totalCost > 0
                    ? RoundAmount(item.TotalAmount / totalCost * 100m)
                    : 0m
            })
            .ToList();

        return new FinanceCostAnalysisDto
        {
            Dimension = ToDimensionCode(snapshot.Dimension),
            StoreId = snapshot.StoreId?.ToString(CultureInfo.InvariantCulture),
            Month = ToMonthText(snapshot.CostMonth),
            Stats = new FinanceCostAnalysisStatsDto
            {
                TotalCost = totalCost,
                FoodCostRate = foodCostRate,
                AverageCostPerPaidOrder = averageCostPerPaidOrder,
                MonthOnMonthChangeRate = RoundAmount(snapshot.MonthOnMonthChangeRate),
                Revenue = RoundAmount(snapshot.CurrentRevenue),
                PaidOrderCount = snapshot.CurrentPaidOrderCount
            },
            Trend = trend,
            Composition = composition,
            DetailRows = detailRows
        };
    }

    /// <summary>
    /// 归一化为月份起始 UTC 时间。
    /// </summary>
    public static DateTime NormalizeMonthStart(DateTime value)
    {
        var utcValue = value.Kind switch
        {
            DateTimeKind.Utc => value,
            DateTimeKind.Local => value.ToUniversalTime(),
            _ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
        };

        return new DateTime(utcValue.Year, utcValue.Month, 1, 0, 0, 0, DateTimeKind.Utc);
    }
}
