using MediatR;
using TakeoutSaaS.Application.App.Coupons.FullReduction.Dto;
using TakeoutSaaS.Application.App.Coupons.FullReduction.Queries;
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.FullReduction.Handlers;

/// <summary>
/// 满减活动列表查询处理器。
/// </summary>
public sealed class GetFullReductionCampaignListQueryHandler(
    IPromotionCampaignRepository promotionCampaignRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetFullReductionCampaignListQuery, FullReductionListResultDto>
{
    /// <inheritdoc />
    public async Task<FullReductionListResultDto> Handle(GetFullReductionCampaignListQuery request, CancellationToken cancellationToken)
    {
        var page = Math.Max(1, request.Page);
        var pageSize = Math.Clamp(request.PageSize, 1, 200);

        if (!FullReductionMapping.TryNormalizeDisplayStatusFilter(request.Status, out var normalizedStatus))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "status 参数不合法");
        }

        if (!FullReductionMapping.TryNormalizeActivityTypeFilter(request.ActivityType, out var normalizedActivityType))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "activityType 参数不合法");
        }

        var tenantId = tenantProvider.GetCurrentTenantId();
        if (request.VisibleStoreIds.Count == 0)
        {
            return new FullReductionListResultDto
            {
                Items = [],
                TotalCount = 0,
                Page = page,
                PageSize = pageSize,
                Stats = new FullReductionStatsDto()
            };
        }

        var campaigns = await promotionCampaignRepository.GetByPromotionTypeAsync(
            tenantId,
            PromotionType.FullReduction,
            cancellationToken);

        if (campaigns.Count == 0)
        {
            return new FullReductionListResultDto
            {
                Items = [],
                TotalCount = 0,
                Page = page,
                PageSize = pageSize,
                Stats = new FullReductionStatsDto()
            };
        }

        var nowUtc = DateTime.UtcNow;

        var visibleItems = new List<FullReductionListItemDto>(campaigns.Count);
        foreach (var campaign in campaigns)
        {
            var rules = FullReductionMapping.DeserializeRules(campaign.RulesJson, campaign.Id);
            if (!FullReductionMapping.HasVisibleStore(rules, request.VisibleStoreIds))
            {
                continue;
            }

            visibleItems.Add(FullReductionDtoFactory.ToListItemDto(campaign, rules, nowUtc));
        }

        var stats = FullReductionDtoFactory.ToStatsDto(visibleItems);

        IEnumerable<FullReductionListItemDto> filtered = visibleItems;
        if (!string.IsNullOrWhiteSpace(normalizedActivityType))
        {
            filtered = filtered.Where(item =>
                string.Equals(item.Rules.ActivityType, normalizedActivityType, StringComparison.Ordinal));
        }

        if (!string.IsNullOrWhiteSpace(normalizedStatus))
        {
            filtered = filtered.Where(item =>
                string.Equals(item.DisplayStatus, normalizedStatus, StringComparison.Ordinal));
        }

        var keyword = request.Keyword?.Trim();
        if (!string.IsNullOrWhiteSpace(keyword))
        {
            filtered = filtered.Where(item =>
                item.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase));
        }

        var ordered = filtered
            .OrderByDescending(item => item.UpdatedAt)
            .ThenByDescending(item => item.Id)
            .ToList();

        var total = ordered.Count;
        var paged = ordered
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToList();

        return new FullReductionListResultDto
        {
            Items = paged,
            TotalCount = total,
            Page = page,
            PageSize = pageSize,
            Stats = stats
        };
    }
}
