using MediatR;
using TakeoutSaaS.Application.App.Coupons.Calendar.Dto;
using TakeoutSaaS.Application.App.Coupons.Calendar.Queries;
using TakeoutSaaS.Application.App.Coupons.FlashSale;
using TakeoutSaaS.Application.App.Coupons.FlashSale.Dto;
using TakeoutSaaS.Application.App.Coupons.FullReduction;
using TakeoutSaaS.Application.App.Coupons.FullReduction.Dto;
using TakeoutSaaS.Application.App.Coupons.PunchCard;
using TakeoutSaaS.Application.App.Coupons.Seckill;
using TakeoutSaaS.Application.App.Coupons.Seckill.Dto;
using TakeoutSaaS.Domain.Coupons.Entities;
using TakeoutSaaS.Domain.Coupons.Enums;
using TakeoutSaaS.Domain.Coupons.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Coupons.Calendar.Handlers;

public sealed class GetMarketingCalendarOverviewQueryHandler(
    IPromotionCampaignRepository promotionCampaignRepository,
    ICouponRepository couponRepository,
    IPunchCardRepository punchCardRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetMarketingCalendarOverviewQuery, MarketingCalendarOverviewDto>
{
    private const string SourceTypeCoupon = "coupon";
    private const string SourceTypeFlashSale = "flash_sale";
    private const string SourceTypeFullReduction = "full_reduction";
    private const string SourceTypePunchCard = "punch_card";
    private const string SourceTypeSeckill = "seckill";

    private const string CalendarTypeCoupon = "coupon";
    private const string CalendarTypeFlashSale = "flash_sale";
    private const string CalendarTypeGift = "gift";
    private const string CalendarTypePunchCard = "punch_card";
    private const string CalendarTypeReduce = "reduce";
    private const string CalendarTypeSecondHalf = "second_half";
    private const string CalendarTypeSeckill = "seckill";

    private const string DisplayStatusDisabled = "disabled";
    private const string DisplayStatusEnded = "ended";
    private const string DisplayStatusOngoing = "ongoing";
    private const string DisplayStatusUpcoming = "upcoming";

    public async Task<MarketingCalendarOverviewDto> Handle(
        GetMarketingCalendarOverviewQuery request,
        CancellationToken cancellationToken)
    {
        if (request.Year is < 2000 or > 2100)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "year 参数不合法");
        }

        if (request.Month is < 1 or > 12)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "month 参数不合法");
        }

        var tenantId = tenantProvider.GetCurrentTenantId();
        var monthStart = new DateTime(request.Year, request.Month, 1, 0, 0, 0, DateTimeKind.Utc);
        var monthEnd = monthStart.AddMonths(1).AddDays(-1);
        var daysInMonth = DateTime.DaysInMonth(request.Year, request.Month);
        var nowUtc = DateTime.UtcNow;

        var activities = new List<CalendarActivityAggregate>(64);
        activities.AddRange(await BuildFullReductionAsync(tenantId, request.StoreId, monthStart, monthEnd, daysInMonth, nowUtc, cancellationToken));
        activities.AddRange(await BuildFlashSaleAsync(tenantId, request.StoreId, monthStart, monthEnd, daysInMonth, nowUtc, cancellationToken));
        activities.AddRange(await BuildSeckillAsync(tenantId, request.StoreId, monthStart, monthEnd, daysInMonth, nowUtc, cancellationToken));
        activities.AddRange(await BuildCouponAsync(tenantId, request.StoreId, monthStart, monthEnd, daysInMonth, nowUtc, cancellationToken));
        activities.AddRange(await BuildPunchCardAsync(tenantId, request.StoreId, monthStart, monthEnd, daysInMonth, nowUtc, cancellationToken));

        var visible = activities
            .Where(item => item.CoveredDays.Count > 0)
            .OrderBy(item => item.TypeOrder)
            .ThenBy(item => item.Activity.StartDate)
            .ThenBy(item => item.Activity.Name, StringComparer.Ordinal)
            .ThenBy(item => item.Activity.ActivityId, StringComparer.Ordinal)
            .ToList();

        var activityMap = visible.ToDictionary(item => item.Activity.ActivityId, item => item.Activity);
        var dayBuckets = BuildDayBuckets(daysInMonth, visible);
        var conflicts = BuildConflicts(dayBuckets, activityMap);
        var banner = BuildConflictBanner(conflicts);

        var estimatedDiscountAmount = decimal.Round(
            visible.Sum(item => item.Activity.EstimatedDiscountAmount),
            2,
            MidpointRounding.AwayFromZero);

        return new MarketingCalendarOverviewDto
        {
            Month = $"{request.Year:D4}-{request.Month:D2}",
            Year = request.Year,
            MonthValue = request.Month,
            MonthStartDate = monthStart,
            MonthEndDate = monthEnd,
            TodayDay = nowUtc.Year == request.Year && nowUtc.Month == request.Month ? nowUtc.Day : 0,
            Days = BuildMonthDays(monthStart, daysInMonth, nowUtc),
            Legends = BuildLegends(),
            Stats = new MarketingCalendarStatsDto
            {
                TotalActivityCount = visible.Count,
                OngoingCount = visible.Count(item => string.Equals(item.Activity.DisplayStatus, DisplayStatusOngoing, StringComparison.Ordinal)),
                MaxConcurrentCount = dayBuckets.Count == 0 ? 0 : dayBuckets.Values.Max(item => item.Count),
                EstimatedDiscountAmount = estimatedDiscountAmount
            },
            ConflictBanner = banner,
            Conflicts = conflicts,
            Activities = visible.Select(item => item.Activity).ToList()
        };
    }

    private async Task<IReadOnlyList<CalendarActivityAggregate>> BuildFullReductionAsync(
        long tenantId,
        long storeId,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        DateTime nowUtc,
        CancellationToken cancellationToken)
    {
        var campaigns = await promotionCampaignRepository.GetByPromotionTypeAsync(tenantId, PromotionType.FullReduction, cancellationToken);
        if (campaigns.Count == 0)
        {
            return [];
        }

        var results = new List<CalendarActivityAggregate>(campaigns.Count);
        foreach (var campaign in campaigns)
        {
            var rules = FullReductionMapping.DeserializeRules(campaign.RulesJson, campaign.Id);
            if (!FullReductionMapping.HasVisibleStore(rules, [storeId]))
            {
                continue;
            }

            var calendarType = rules.ActivityType switch
            {
                "reduce" => CalendarTypeReduce,
                "gift" => CalendarTypeGift,
                "second_half" => CalendarTypeSecondHalf,
                _ => throw new BusinessException(ErrorCodes.BadRequest, "满减活动类型数据不合法")
            };

            var displayStatus = FullReductionMapping.ResolveDisplayStatus(campaign, nowUtc);
            var summary = BuildFullReductionSummary(rules);
            var isDimmed = FullReductionMapping.IsDimmed(displayStatus);
            var activityId = $"{SourceTypeFullReduction}:{campaign.Id}";
            var (bars, coveredDays) = BuildRangeBars(
                activityId,
                NormalizeUtcDate(campaign.StartAt),
                NormalizeUtcDate(campaign.EndAt),
                monthStart,
                monthEnd,
                daysInMonth,
                summary,
                isDimmed);

            if (coveredDays.Count == 0)
            {
                continue;
            }

            var estimate = decimal.Round(Math.Max(0m, rules.Metrics.DiscountTotalAmount), 2, MidpointRounding.AwayFromZero);
            results.Add(CreateAggregate(
                ResolveTypeOrder(calendarType),
                coveredDays,
                new MarketingCalendarActivityDto
                {
                    ActivityId = activityId,
                    SourceType = SourceTypeFullReduction,
                    SourceId = campaign.Id.ToString(),
                    CalendarType = calendarType,
                    Name = campaign.Name,
                    Color = ResolveColor(calendarType),
                    Summary = summary,
                    DisplayStatus = displayStatus,
                    IsDimmed = isDimmed,
                    StartDate = NormalizeUtcDate(campaign.StartAt),
                    EndDate = NormalizeUtcDate(campaign.EndAt),
                    EstimatedDiscountAmount = estimate,
                    Bars = bars,
                    Detail = new MarketingCalendarActivityDetailDto
                    {
                        ModuleName = "满减活动",
                        Description = "按规则触发减免优惠。",
                        Fields =
                        [
                            new MarketingCalendarDetailFieldDto { Label = "活动类型", Value = ResolveCalendarTypeLabel(calendarType) },
                            new MarketingCalendarDetailFieldDto { Label = "活动时间", Value = $"{NormalizeUtcDate(campaign.StartAt):yyyy-MM-dd} ~ {NormalizeUtcDate(campaign.EndAt):yyyy-MM-dd}" },
                            new MarketingCalendarDetailFieldDto { Label = "适用门店数", Value = rules.StoreIds.Count.ToString() },
                            new MarketingCalendarDetailFieldDto { Label = "预计优惠", Value = FormatCurrency(estimate) }
                        ]
                    }
                }));
        }

        return results;
    }

    private async Task<IReadOnlyList<CalendarActivityAggregate>> BuildFlashSaleAsync(
        long tenantId,
        long storeId,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        DateTime nowUtc,
        CancellationToken cancellationToken)
    {
        var campaigns = await promotionCampaignRepository.GetByPromotionTypeAsync(tenantId, PromotionType.FlashSale, cancellationToken);
        if (campaigns.Count == 0)
        {
            return [];
        }

        var results = new List<CalendarActivityAggregate>(campaigns.Count);
        foreach (var campaign in campaigns)
        {
            var rules = FlashSaleMapping.DeserializeRules(campaign.RulesJson, campaign.Id);
            if (!FlashSaleMapping.HasVisibleStore(rules, [storeId]))
            {
                continue;
            }

            var displayStatus = FlashSaleMapping.ResolveDisplayStatus(campaign, rules, nowUtc);
            var isDimmed = FlashSaleMapping.IsDimmed(displayStatus);
            var summary = BuildFlashSaleSummary(rules);
            var activityId = $"{SourceTypeFlashSale}:{campaign.Id}";
            var bars = new List<MarketingCalendarActivityBarDto>();
            var coveredDays = new HashSet<int>();
            if (string.Equals(rules.CycleType, "recurring", StringComparison.Ordinal) && rules.WeekDays.Count > 0)
            {
                var startDate = NormalizeUtcDate(campaign.StartAt);
                var endDate = NormalizeUtcDate(campaign.EndAt);
                for (var day = 1; day <= daysInMonth; day++)
                {
                    var currentDate = monthStart.AddDays(day - 1);
                    if (currentDate < startDate || currentDate > endDate)
                    {
                        continue;
                    }

                    if (!rules.WeekDays.Contains(ToWeekDayValue(currentDate.DayOfWeek)))
                    {
                        continue;
                    }

                    bars.Add(new MarketingCalendarActivityBarDto
                    {
                        BarId = $"{activityId}:bar:{bars.Count + 1}",
                        StartDay = day,
                        EndDay = day,
                        Label = string.Empty,
                        IsMilestone = true,
                        IsDimmed = isDimmed
                    });
                    coveredDays.Add(day);
                }
            }
            else
            {
                var range = BuildRangeBars(
                    activityId,
                    NormalizeUtcDate(campaign.StartAt),
                    NormalizeUtcDate(campaign.EndAt),
                    monthStart,
                    monthEnd,
                    daysInMonth,
                    summary,
                    isDimmed);
                bars.AddRange(range.Bars);
                coveredDays.UnionWith(range.CoveredDays);
            }

            if (coveredDays.Count == 0)
            {
                continue;
            }

            var estimate = decimal.Round(Math.Max(0m, rules.Metrics.DiscountTotalAmount), 2, MidpointRounding.AwayFromZero);
            results.Add(CreateAggregate(
                ResolveTypeOrder(CalendarTypeFlashSale),
                coveredDays,
                new MarketingCalendarActivityDto
                {
                    ActivityId = activityId,
                    SourceType = SourceTypeFlashSale,
                    SourceId = campaign.Id.ToString(),
                    CalendarType = CalendarTypeFlashSale,
                    Name = campaign.Name,
                    Color = ResolveColor(CalendarTypeFlashSale),
                    Summary = summary,
                    DisplayStatus = displayStatus,
                    IsDimmed = isDimmed,
                    StartDate = NormalizeUtcDate(campaign.StartAt),
                    EndDate = NormalizeUtcDate(campaign.EndAt),
                    EstimatedDiscountAmount = estimate,
                    Bars = bars,
                    Detail = new MarketingCalendarActivityDetailDto
                    {
                        ModuleName = "限时折扣",
                        Description = "按时间段对指定商品执行折扣。",
                        Fields =
                        [
                            new MarketingCalendarDetailFieldDto { Label = "活动周期", Value = string.Equals(rules.CycleType, "recurring", StringComparison.Ordinal) ? "循环活动" : "单次活动" },
                            new MarketingCalendarDetailFieldDto { Label = "活动日期", Value = $"{NormalizeUtcDate(campaign.StartAt):yyyy-MM-dd} ~ {NormalizeUtcDate(campaign.EndAt):yyyy-MM-dd}" },
                            new MarketingCalendarDetailFieldDto { Label = "参与商品数", Value = rules.Products.Count.ToString() },
                            new MarketingCalendarDetailFieldDto { Label = "预计优惠", Value = FormatCurrency(estimate) }
                        ]
                    }
                }));
        }

        return results;
    }

    private async Task<IReadOnlyList<CalendarActivityAggregate>> BuildSeckillAsync(
        long tenantId,
        long storeId,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        DateTime nowUtc,
        CancellationToken cancellationToken)
    {
        var campaigns = await promotionCampaignRepository.GetByPromotionTypeAsync(tenantId, PromotionType.Seckill, cancellationToken);
        if (campaigns.Count == 0)
        {
            return [];
        }

        var results = new List<CalendarActivityAggregate>(campaigns.Count);
        foreach (var campaign in campaigns)
        {
            var rules = SeckillMapping.DeserializeRules(campaign.RulesJson, campaign.Id);
            if (!SeckillMapping.HasVisibleStore(rules, [storeId]))
            {
                continue;
            }

            var displayStatus = SeckillMapping.ResolveDisplayStatus(campaign, rules, nowUtc);
            var isDimmed = SeckillMapping.IsDimmed(displayStatus);
            var summary = BuildSeckillSummary(rules);
            var estimate = ComputeSeckillEstimatedDiscount(rules.Products);
            var activityId = $"{SourceTypeSeckill}:{campaign.Id}";
            var (bars, coveredDays) = BuildRangeBars(
                activityId,
                NormalizeUtcDate(campaign.StartAt),
                NormalizeUtcDate(campaign.EndAt),
                monthStart,
                monthEnd,
                daysInMonth,
                summary,
                isDimmed);

            if (coveredDays.Count == 0)
            {
                continue;
            }

            results.Add(CreateAggregate(
                ResolveTypeOrder(CalendarTypeSeckill),
                coveredDays,
                new MarketingCalendarActivityDto
                {
                    ActivityId = activityId,
                    SourceType = SourceTypeSeckill,
                    SourceId = campaign.Id.ToString(),
                    CalendarType = CalendarTypeSeckill,
                    Name = campaign.Name,
                    Color = ResolveColor(CalendarTypeSeckill),
                    Summary = summary,
                    DisplayStatus = displayStatus,
                    IsDimmed = isDimmed,
                    StartDate = NormalizeUtcDate(campaign.StartAt),
                    EndDate = NormalizeUtcDate(campaign.EndAt),
                    EstimatedDiscountAmount = estimate,
                    Bars = bars,
                    Detail = new MarketingCalendarActivityDetailDto
                    {
                        ModuleName = "秒杀活动",
                        Description = "按场次执行限量秒杀。",
                        Fields =
                        [
                            new MarketingCalendarDetailFieldDto { Label = "活动类型", Value = string.Equals(rules.ActivityType, "hourly", StringComparison.Ordinal) ? "整点秒杀" : "限时秒杀" },
                            new MarketingCalendarDetailFieldDto { Label = "活动日期", Value = $"{NormalizeUtcDate(campaign.StartAt):yyyy-MM-dd} ~ {NormalizeUtcDate(campaign.EndAt):yyyy-MM-dd}" },
                            new MarketingCalendarDetailFieldDto { Label = "参与商品数", Value = rules.Products.Count.ToString() },
                            new MarketingCalendarDetailFieldDto { Label = "预计优惠", Value = FormatCurrency(estimate) }
                        ]
                    }
                }));
        }

        return results;
    }

    private async Task<IReadOnlyList<CalendarActivityAggregate>> BuildCouponAsync(
        long tenantId,
        long storeId,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        DateTime nowUtc,
        CancellationToken cancellationToken)
    {
        var templates = await couponRepository.GetTemplatesAsync(tenantId, cancellationToken);
        if (templates.Count == 0)
        {
            return [];
        }

        var results = new List<CalendarActivityAggregate>(templates.Count);
        foreach (var template in templates)
        {
            var storeScope = CouponTemplateMapping.DeserializeStoreScope(template.StoreScopeJson, template.Id);
            if (!storeScope.StoreIds.Contains(storeId))
            {
                continue;
            }

            var channels = CouponTemplateMapping.DeserializeChannels(template.ChannelsJson, template.Id);
            var displayStatus = CouponTemplateMapping.ResolveDisplayStatus(template, nowUtc);
            var isDimmed = CouponTemplateMapping.IsDimmedDisplayStatus(displayStatus);
            var summary = BuildCouponSummary(template);
            var estimate = ComputeCouponEstimatedDiscount(template);
            var activityId = $"{SourceTypeCoupon}:{template.Id}";

            DateTime startDate;
            DateTime endDate;
            if (template.ValidFrom.HasValue && template.ValidTo.HasValue)
            {
                startDate = NormalizeUtcDate(template.ValidFrom.Value);
                endDate = NormalizeUtcDate(template.ValidTo.Value);
            }
            else
            {
                startDate = monthStart;
                endDate = monthEnd;
            }

            var (bars, coveredDays) = BuildRangeBars(
                activityId,
                startDate,
                endDate,
                monthStart,
                monthEnd,
                daysInMonth,
                summary,
                isDimmed);
            if (coveredDays.Count == 0)
            {
                continue;
            }

            results.Add(CreateAggregate(
                ResolveTypeOrder(CalendarTypeCoupon),
                coveredDays,
                new MarketingCalendarActivityDto
                {
                    ActivityId = activityId,
                    SourceType = SourceTypeCoupon,
                    SourceId = template.Id.ToString(),
                    CalendarType = CalendarTypeCoupon,
                    Name = template.Name,
                    Color = ResolveColor(CalendarTypeCoupon),
                    Summary = summary,
                    DisplayStatus = displayStatus,
                    IsDimmed = isDimmed,
                    StartDate = startDate,
                    EndDate = endDate,
                    EstimatedDiscountAmount = estimate,
                    Bars = bars,
                    Detail = new MarketingCalendarActivityDetailDto
                    {
                        ModuleName = "优惠券",
                        Description = "按券模板规则领取与核销。",
                        Fields =
                        [
                            new MarketingCalendarDetailFieldDto { Label = "券类型", Value = ResolveCouponTypeLabel(template.CouponType) },
                            new MarketingCalendarDetailFieldDto { Label = "券规则", Value = summary },
                            new MarketingCalendarDetailFieldDto { Label = "有效期", Value = ResolveCouponValidityText(template) },
                            new MarketingCalendarDetailFieldDto { Label = "渠道", Value = FormatChannels(channels) },
                            new MarketingCalendarDetailFieldDto { Label = "预计优惠", Value = FormatCurrency(estimate) }
                        ]
                    }
                }));
        }

        return results;
    }

    private async Task<IReadOnlyList<CalendarActivityAggregate>> BuildPunchCardAsync(
        long tenantId,
        long storeId,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        DateTime nowUtc,
        CancellationToken cancellationToken)
    {
        var templates = await punchCardRepository.GetTemplatesByStoreAsync(tenantId, storeId, cancellationToken);
        if (templates.Count == 0)
        {
            return [];
        }

        var templateIds = templates.Select(item => item.Id).ToList();
        var aggregateMap = await punchCardRepository.GetTemplateAggregateByTemplateIdsAsync(
            tenantId,
            storeId,
            templateIds,
            cancellationToken);

        var results = new List<CalendarActivityAggregate>(templates.Count);
        foreach (var template in templates)
        {
            var soldCount = aggregateMap.TryGetValue(template.Id, out var aggregate) ? aggregate.SoldCount : 0;
            var activeCount = aggregateMap.TryGetValue(template.Id, out var activeAggregate) ? activeAggregate.ActiveCount : 0;
            var displayStatus = ResolvePunchCardDisplayStatus(template, nowUtc);
            var isDimmed = string.Equals(displayStatus, DisplayStatusDisabled, StringComparison.Ordinal)
                           || string.Equals(displayStatus, DisplayStatusEnded, StringComparison.Ordinal);
            var summary = BuildPunchCardSummary(template);
            var estimate = ComputePunchCardEstimatedDiscount(template, soldCount);
            var activityId = $"{SourceTypePunchCard}:{template.Id}";

            DateTime startDate;
            DateTime endDate;
            if (template.ValidityType == PunchCardValidityType.DateRange && template.ValidFrom.HasValue && template.ValidTo.HasValue)
            {
                startDate = NormalizeUtcDate(template.ValidFrom.Value);
                endDate = NormalizeUtcDate(template.ValidTo.Value);
            }
            else
            {
                startDate = monthStart;
                endDate = monthEnd;
            }

            var (bars, coveredDays) = BuildRangeBars(
                activityId,
                startDate,
                endDate,
                monthStart,
                monthEnd,
                daysInMonth,
                summary,
                isDimmed);
            if (coveredDays.Count == 0)
            {
                continue;
            }

            results.Add(CreateAggregate(
                ResolveTypeOrder(CalendarTypePunchCard),
                coveredDays,
                new MarketingCalendarActivityDto
                {
                    ActivityId = activityId,
                    SourceType = SourceTypePunchCard,
                    SourceId = template.Id.ToString(),
                    CalendarType = CalendarTypePunchCard,
                    Name = template.Name,
                    Color = ResolveColor(CalendarTypePunchCard),
                    Summary = summary,
                    DisplayStatus = displayStatus,
                    IsDimmed = isDimmed,
                    StartDate = startDate,
                    EndDate = endDate,
                    EstimatedDiscountAmount = estimate,
                    Bars = bars,
                    Detail = new MarketingCalendarActivityDetailDto
                    {
                        ModuleName = "次卡管理",
                        Description = "次卡模板上架后可持续售卖和核销。",
                        Fields =
                        [
                            new MarketingCalendarDetailFieldDto { Label = "售价", Value = FormatCurrency(template.SalePrice) },
                            new MarketingCalendarDetailFieldDto { Label = "总次数", Value = $"{template.TotalTimes}次" },
                            new MarketingCalendarDetailFieldDto { Label = "有效期", Value = PunchCardMapping.BuildValiditySummary(template) },
                            new MarketingCalendarDetailFieldDto { Label = "已售", Value = soldCount.ToString() },
                            new MarketingCalendarDetailFieldDto { Label = "使用中", Value = activeCount.ToString() }
                        ]
                    }
                }));
        }

        return results;
    }

    private static Dictionary<int, List<string>> BuildDayBuckets(
        int daysInMonth,
        IReadOnlyCollection<CalendarActivityAggregate> activities)
    {
        var buckets = new Dictionary<int, List<string>>(daysInMonth);
        for (var day = 1; day <= daysInMonth; day++)
        {
            buckets[day] = [];
        }

        foreach (var activity in activities)
        {
            foreach (var day in activity.CoveredDays)
            {
                if (day is >= 1 and <= 31 && buckets.ContainsKey(day))
                {
                    buckets[day].Add(activity.Activity.ActivityId);
                }
            }
        }

        return buckets;
    }

    private static IReadOnlyList<MarketingCalendarConflictDto> BuildConflicts(
        IReadOnlyDictionary<int, List<string>> dayBuckets,
        IReadOnlyDictionary<string, MarketingCalendarActivityDto> activityMap)
    {
        if (dayBuckets.Count == 0)
        {
            return [];
        }

        var maxDay = dayBuckets.Keys.Max();
        var results = new List<MarketingCalendarConflictDto>();
        var day = 1;
        while (day <= maxDay)
        {
            if (!dayBuckets.TryGetValue(day, out var daily) || daily.Count < 2)
            {
                day++;
                continue;
            }

            var startDay = day;
            var maxConcurrent = 0;
            var activityIds = new HashSet<string>(StringComparer.Ordinal);
            while (day <= maxDay &&
                   dayBuckets.TryGetValue(day, out var current) &&
                   current.Count >= 2)
            {
                maxConcurrent = Math.Max(maxConcurrent, current.Count);
                foreach (var activityId in current)
                {
                    activityIds.Add(activityId);
                }

                day++;
            }

            var endDay = day - 1;
            var sortedIds = activityIds.OrderBy(item => item, StringComparer.Ordinal).ToList();
            var summaries = sortedIds
                .Where(activityMap.ContainsKey)
                .Select(item => activityMap[item])
                .Select(item => new MarketingCalendarConflictActivityDto
                {
                    ActivityId = item.ActivityId,
                    CalendarType = item.CalendarType,
                    Name = item.Name,
                    Summary = item.Summary,
                    Color = item.Color,
                    DisplayStatus = item.DisplayStatus
                })
                .ToList();

            results.Add(new MarketingCalendarConflictDto
            {
                ConflictId = $"conflict:{startDay:D2}-{endDay:D2}",
                StartDay = startDay,
                EndDay = endDay,
                ActivityCount = maxConcurrent,
                MaxConcurrentCount = maxConcurrent,
                ActivityIds = sortedIds,
                Activities = summaries
            });
        }

        return results;
    }

    private static MarketingCalendarConflictBannerDto? BuildConflictBanner(IReadOnlyList<MarketingCalendarConflictDto> conflicts)
    {
        if (conflicts.Count == 0)
        {
            return null;
        }

        var selected = conflicts
            .OrderByDescending(item => item.MaxConcurrentCount)
            .ThenByDescending(item => item.EndDay - item.StartDay + 1)
            .ThenBy(item => item.StartDay)
            .First();

        return new MarketingCalendarConflictBannerDto
        {
            ConflictId = selected.ConflictId,
            StartDay = selected.StartDay,
            EndDay = selected.EndDay,
            ActivityCount = selected.ActivityCount,
            MaxConcurrentCount = selected.MaxConcurrentCount,
            ConflictCount = conflicts.Count
        };
    }

    private static IReadOnlyList<MarketingCalendarDayDto> BuildMonthDays(DateTime monthStart, int daysInMonth, DateTime nowUtc)
    {
        var result = new List<MarketingCalendarDayDto>(daysInMonth);
        var isCurrentMonth = monthStart.Year == nowUtc.Year && monthStart.Month == nowUtc.Month;
        for (var day = 1; day <= daysInMonth; day++)
        {
            var date = monthStart.AddDays(day - 1);
            result.Add(new MarketingCalendarDayDto
            {
                Day = day,
                IsWeekend = date.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday,
                IsToday = isCurrentMonth && day == nowUtc.Day
            });
        }

        return result;
    }

    private static IReadOnlyList<MarketingCalendarLegendDto> BuildLegends()
    {
        return
        [
            new MarketingCalendarLegendDto { Type = CalendarTypeReduce, Label = "满减", Color = ResolveColor(CalendarTypeReduce) },
            new MarketingCalendarLegendDto { Type = CalendarTypeGift, Label = "满赠", Color = ResolveColor(CalendarTypeGift) },
            new MarketingCalendarLegendDto { Type = CalendarTypeSecondHalf, Label = "第二份半价", Color = ResolveColor(CalendarTypeSecondHalf) },
            new MarketingCalendarLegendDto { Type = CalendarTypeFlashSale, Label = "限时折扣", Color = ResolveColor(CalendarTypeFlashSale) },
            new MarketingCalendarLegendDto { Type = CalendarTypeSeckill, Label = "秒杀", Color = ResolveColor(CalendarTypeSeckill) },
            new MarketingCalendarLegendDto { Type = CalendarTypeCoupon, Label = "优惠券", Color = ResolveColor(CalendarTypeCoupon) },
            new MarketingCalendarLegendDto { Type = CalendarTypePunchCard, Label = "次卡", Color = ResolveColor(CalendarTypePunchCard) }
        ];
    }

    private static (IReadOnlyList<MarketingCalendarActivityBarDto> Bars, HashSet<int> CoveredDays) BuildRangeBars(
        string activityId,
        DateTime startDate,
        DateTime endDate,
        DateTime monthStart,
        DateTime monthEnd,
        int daysInMonth,
        string label,
        bool isDimmed)
    {
        if (!TryClipRange(startDate, endDate, monthStart, monthEnd, out var startDay, out var endDay))
        {
            return ([], []);
        }

        var bars = new List<MarketingCalendarActivityBarDto>(1)
        {
            new()
            {
                BarId = $"{activityId}:bar:1",
                StartDay = startDay,
                EndDay = endDay,
                Label = label,
                IsMilestone = false,
                IsDimmed = isDimmed
            }
        };

        var coveredDays = Enumerable.Range(startDay, Math.Max(1, endDay - startDay + 1))
            .Where(day => day <= daysInMonth)
            .ToHashSet();

        return (bars, coveredDays);
    }

    private static bool TryClipRange(DateTime startDate, DateTime endDate, DateTime monthStart, DateTime monthEnd, out int startDay, out int endDay)
    {
        var normalizedStart = NormalizeUtcDate(startDate);
        var normalizedEnd = NormalizeUtcDate(endDate);
        if (normalizedStart > normalizedEnd)
        {
            (normalizedStart, normalizedEnd) = (normalizedEnd, normalizedStart);
        }

        var clippedStart = normalizedStart < monthStart ? monthStart : normalizedStart;
        var clippedEnd = normalizedEnd > monthEnd ? monthEnd : normalizedEnd;
        if (clippedStart > clippedEnd)
        {
            startDay = 0;
            endDay = 0;
            return false;
        }

        startDay = clippedStart.Day;
        endDay = clippedEnd.Day;
        return true;
    }

    private static DateTime NormalizeUtcDate(DateTime value)
    {
        return value.Kind switch
        {
            DateTimeKind.Utc => value.Date,
            DateTimeKind.Local => value.ToUniversalTime().Date,
            _ => DateTime.SpecifyKind(value.Date, DateTimeKind.Utc)
        };
    }

    private static CalendarActivityAggregate CreateAggregate(
        int typeOrder,
        HashSet<int> coveredDays,
        MarketingCalendarActivityDto activity)
    {
        return new CalendarActivityAggregate
        {
            TypeOrder = typeOrder,
            CoveredDays = coveredDays,
            Activity = activity
        };
    }

    private static int ResolveTypeOrder(string calendarType)
    {
        return calendarType switch
        {
            CalendarTypeReduce => 10,
            CalendarTypeGift => 20,
            CalendarTypeSecondHalf => 30,
            CalendarTypeFlashSale => 40,
            CalendarTypeSeckill => 50,
            CalendarTypeCoupon => 60,
            CalendarTypePunchCard => 70,
            _ => 999
        };
    }

    private static string ResolveColor(string calendarType)
    {
        return calendarType switch
        {
            CalendarTypeReduce => "#3b82f6",
            CalendarTypeGift => "#22c55e",
            CalendarTypeSecondHalf => "#f59e0b",
            CalendarTypeFlashSale => "#8b5cf6",
            CalendarTypeSeckill => "#ef4444",
            CalendarTypeCoupon => "#ec4899",
            CalendarTypePunchCard => "#06b6d4",
            _ => "#64748b"
        };
    }

    private static string ResolveCalendarTypeLabel(string calendarType)
    {
        return calendarType switch
        {
            CalendarTypeReduce => "满减",
            CalendarTypeGift => "满赠",
            CalendarTypeSecondHalf => "第二份半价",
            CalendarTypeFlashSale => "限时折扣",
            CalendarTypeSeckill => "秒杀",
            CalendarTypeCoupon => "优惠券",
            CalendarTypePunchCard => "次卡",
            _ => "活动"
        };
    }

    private static string ResolveCouponTypeLabel(CouponType couponType)
    {
        return couponType switch
        {
            CouponType.AmountOff => "满减券",
            CouponType.Percentage => "折扣券",
            CouponType.Cash => "现金券",
            CouponType.DeliveryFee => "免配送费券",
            CouponType.Gift => "礼品券",
            _ => "优惠券"
        };
    }

    private static string ResolveCouponValidityText(CouponTemplate template)
    {
        if (template.ValidFrom.HasValue && template.ValidTo.HasValue)
        {
            return $"{NormalizeUtcDate(template.ValidFrom.Value):yyyy-MM-dd} ~ {NormalizeUtcDate(template.ValidTo.Value):yyyy-MM-dd}";
        }

        if (template.RelativeValidDays.HasValue && template.RelativeValidDays.Value > 0)
        {
            return $"领取后{template.RelativeValidDays.Value}天内有效";
        }

        return "长期有效";
    }

    private static string BuildFullReductionSummary(FullReductionRulesDto rules)
    {
        return rules.ActivityType switch
        {
            "reduce" => string.Join(" / ", rules.ReduceTiers.OrderBy(item => item.MeetAmount).Take(3).Select(item => $"满{item.MeetAmount:0.##}减{item.ReduceAmount:0.##}")),
            "gift" when rules.GiftRule is not null => $"买{rules.GiftRule.BuyQuantity}赠{rules.GiftRule.GiftQuantity}",
            "second_half" when rules.SecondHalfRule is not null => rules.SecondHalfRule.DiscountType switch
            {
                "half" => "第2份5折",
                "sixty" => "第2份6折",
                "seventy" => "第2份7折",
                "free" => "第2份免单",
                _ => "第二份半价"
            },
            _ => "满减活动"
        };
    }

    private static string BuildFlashSaleSummary(FlashSaleRulesDto rules)
    {
        if (string.Equals(rules.CycleType, "recurring", StringComparison.Ordinal) && rules.WeekDays.Count > 0)
        {
            return $"每周{string.Join("、", rules.WeekDays.OrderBy(item => item).Select(ToWeekDayText))}限时折扣";
        }

        if (rules.Products.Count > 0)
        {
            return rules.Products.Count == 1
                ? $"{rules.Products[0].Name}限时折扣"
                : $"{rules.Products[0].Name}等{rules.Products.Count}款限时折扣";
        }

        return "限时折扣";
    }

    private static string BuildSeckillSummary(SeckillRulesDto rules)
    {
        if (rules.Products.Count > 0)
        {
            return $"¥{rules.Products[0].SeckillPrice:0.##} {rules.Products[0].Name}";
        }

        return string.Equals(rules.ActivityType, "hourly", StringComparison.Ordinal) ? "整点秒杀" : "秒杀活动";
    }

    private static string BuildCouponSummary(CouponTemplate template)
    {
        var prefix = template.MinimumSpend.HasValue && template.MinimumSpend.Value > 0
            ? $"满{template.MinimumSpend.Value:0.##}"
            : string.Empty;

        return template.CouponType switch
        {
            CouponType.AmountOff => string.IsNullOrWhiteSpace(prefix) ? $"减{template.Value:0.##}" : $"{prefix}减{template.Value:0.##}",
            CouponType.Cash => string.IsNullOrWhiteSpace(prefix) ? $"减{template.Value:0.##}" : $"{prefix}减{template.Value:0.##}",
            CouponType.Percentage => $"{template.Value:0.##}折优惠",
            CouponType.DeliveryFee => "免配送费",
            CouponType.Gift => "礼品兑换券",
            _ => "优惠券"
        };
    }

    private static string BuildPunchCardSummary(PunchCardTemplate template)
    {
        var baseText = $"¥{template.SalePrice:0.##} / {template.TotalTimes}次";
        return template.ValidityType == PunchCardValidityType.Days
            ? $"{baseText}（长期在售）"
            : baseText;
    }

    private static decimal ComputeSeckillEstimatedDiscount(IReadOnlyList<SeckillProductRuleDto> products)
    {
        var total = products.Sum(item =>
        {
            var diff = item.OriginalPrice - item.SeckillPrice;
            return diff > 0 && item.SoldCount > 0 ? diff * item.SoldCount : 0m;
        });

        return decimal.Round(total, 2, MidpointRounding.AwayFromZero);
    }

    private static decimal ComputeCouponEstimatedDiscount(CouponTemplate template)
    {
        if (template.ClaimedQuantity <= 0)
        {
            return 0m;
        }

        var couponAmount = template.CouponType switch
        {
            CouponType.AmountOff => Math.Max(0m, template.Value),
            CouponType.Cash => Math.Max(0m, template.Value),
            CouponType.DeliveryFee => Math.Max(0m, template.Value),
            _ => 0m
        };

        return decimal.Round(couponAmount * template.ClaimedQuantity, 2, MidpointRounding.AwayFromZero);
    }

    private static decimal ComputePunchCardEstimatedDiscount(PunchCardTemplate template, int soldCount)
    {
        if (!template.OriginalPrice.HasValue || soldCount <= 0)
        {
            return 0m;
        }

        var diff = template.OriginalPrice.Value - template.SalePrice;
        return diff <= 0 ? 0m : decimal.Round(diff * soldCount, 2, MidpointRounding.AwayFromZero);
    }

    private static string ResolvePunchCardDisplayStatus(PunchCardTemplate template, DateTime nowUtc)
    {
        if (template.Status == PunchCardStatus.Disabled)
        {
            return DisplayStatusDisabled;
        }

        if (template.ValidityType == PunchCardValidityType.DateRange && template.ValidFrom.HasValue && template.ValidTo.HasValue)
        {
            var today = NormalizeUtcDate(nowUtc);
            var validFrom = NormalizeUtcDate(template.ValidFrom.Value);
            var validTo = NormalizeUtcDate(template.ValidTo.Value);
            if (today < validFrom)
            {
                return DisplayStatusUpcoming;
            }

            if (today > validTo)
            {
                return DisplayStatusEnded;
            }
        }

        return DisplayStatusOngoing;
    }

    private static int ToWeekDayValue(DayOfWeek dayOfWeek)
    {
        return dayOfWeek switch
        {
            DayOfWeek.Monday => 1,
            DayOfWeek.Tuesday => 2,
            DayOfWeek.Wednesday => 3,
            DayOfWeek.Thursday => 4,
            DayOfWeek.Friday => 5,
            DayOfWeek.Saturday => 6,
            DayOfWeek.Sunday => 7,
            _ => 0
        };
    }

    private static string ToWeekDayText(int value)
    {
        return value switch
        {
            1 => "周一",
            2 => "周二",
            3 => "周三",
            4 => "周四",
            5 => "周五",
            6 => "周六",
            7 => "周日",
            _ => "-"
        };
    }

    private static string FormatChannels(IReadOnlyCollection<string> channels)
    {
        if (channels.Count == 0)
        {
            return "-";
        }

        return string.Join("、", channels.Select(item => item switch
        {
            "delivery" => "外卖",
            "pickup" => "自提",
            "dine_in" => "堂食",
            _ => item
        }));
    }

    private static string FormatCurrency(decimal value)
    {
        return $"¥{value:0.##}";
    }

    private sealed class CalendarActivityAggregate
    {
        public required int TypeOrder { get; init; }
        public required HashSet<int> CoveredDays { get; init; }
        public required MarketingCalendarActivityDto Activity { get; init; }
    }
}
