using MediatR;
using PromotionService.API.Application.DTOs;
using PromotionService.Domain.AggregatesModel.CampaignAggregate;

namespace PromotionService.API.Application.Queries;

/// <summary>
/// EN: Handler for GetCampaignQuery.
/// VI: Handler cho GetCampaignQuery.
/// </summary>
public class GetCampaignQueryHandler : IRequestHandler<GetCampaignQuery, CampaignDto?>
{
    private readonly ICampaignRepository _campaignRepository;

    public GetCampaignQueryHandler(ICampaignRepository campaignRepository)
    {
        _campaignRepository = campaignRepository;
    }

    public async Task<CampaignDto?> Handle(GetCampaignQuery request, CancellationToken cancellationToken)
    {
        var campaign = await _campaignRepository.GetByIdAsync(request.CampaignId);
        return campaign == null ? null : MapToDto(campaign);
    }

    private static CampaignDto MapToDto(Campaign c) => new(
        c.Id, c.MerchantId, c.Name, c.Description,
        c.BackingAssetTypeId == AssetType.Point.Id ? "Point" : "Currency",
        c.BackingAssetCode, c.FaceValue,
        c.AcquisitionTypeId == AcquisitionType.Free.Id ? "Free"
            : c.AcquisitionTypeId == AcquisitionType.ExchangePoints.Id ? "ExchangePoints" : "Purchase",
        c.AcquisitionPrice, c.TotalVouchers, c.IssuedVouchers, c.AvailableVoucherCount,
        c.StartDate, c.EndDate, c.VoucherValidityDays,
        MapStatus(c.StatusId), c.CreatedAt, c.UpdatedAt);

    private static string MapStatus(int statusId) => statusId switch
    {
        1 => "Draft", 2 => "Active", 3 => "Paused", 4 => "Completed", _ => "Cancelled"
    };
}

/// <summary>
/// EN: Handler for GetCampaignsQuery.
/// VI: Handler cho GetCampaignsQuery.
/// </summary>
public class GetCampaignsQueryHandler : IRequestHandler<GetCampaignsQuery, IEnumerable<CampaignSummaryDto>>
{
    private readonly ICampaignRepository _campaignRepository;

    public GetCampaignsQueryHandler(ICampaignRepository campaignRepository)
    {
        _campaignRepository = campaignRepository;
    }

    public async Task<IEnumerable<CampaignSummaryDto>> Handle(GetCampaignsQuery request, CancellationToken cancellationToken)
    {
        IEnumerable<Campaign> campaigns;

        if (request.ActiveOnly)
        {
            campaigns = await _campaignRepository.GetActiveAsync();
        }
        else if (request.MerchantId.HasValue)
        {
            campaigns = await _campaignRepository.GetByMerchantIdAsync(request.MerchantId.Value);
        }
        else
        {
            campaigns = await _campaignRepository.GetActiveAsync();
        }

        return campaigns.Select(c => new CampaignSummaryDto(
            c.Id, c.Name,
            c.StatusId == 1 ? "Draft" : c.StatusId == 2 ? "Active" : c.StatusId == 3 ? "Paused" : c.StatusId == 4 ? "Completed" : "Cancelled",
            c.TotalVouchers, c.IssuedVouchers, c.StartDate, c.EndDate));
    }
}

/// <summary>
/// EN: Handler for ValidateVoucherQuery.
/// VI: Handler cho ValidateVoucherQuery.
/// </summary>
public class ValidateVoucherQueryHandler : IRequestHandler<ValidateVoucherQuery, VoucherValidationDto>
{
    private readonly ICampaignRepository _campaignRepository;

    public ValidateVoucherQueryHandler(ICampaignRepository campaignRepository)
    {
        _campaignRepository = campaignRepository;
    }

    public async Task<VoucherValidationDto> Handle(ValidateVoucherQuery request, CancellationToken cancellationToken)
    {
        var voucher = await _campaignRepository.GetVoucherByCodeAsync(request.VoucherCode);

        if (voucher == null)
            return new VoucherValidationDto(false, "Voucher not found", null, null, null, null, null);

        if (voucher.OwnerId != request.UserId)
            return new VoucherValidationDto(false, "You do not own this voucher", voucher.Id, voucher.Code, null, null, null);

        if (!voucher.IsValidForRedemption())
        {
            var errorMsg = voucher.IsExpired ? "Voucher has expired" : "Voucher cannot be redeemed";
            return new VoucherValidationDto(false, errorMsg, voucher.Id, voucher.Code, voucher.RemainingValue, voucher.ExpiresAt, null);
        }

        var campaign = await _campaignRepository.GetByIdAsync(voucher.CampaignId);

        return new VoucherValidationDto(
            true, null, voucher.Id, voucher.Code,
            voucher.RemainingValue, voucher.ExpiresAt, campaign?.Name);
    }
}

/// <summary>
/// EN: Handler for GetUserVouchersQuery.
/// VI: Handler cho GetUserVouchersQuery.
/// </summary>
public class GetUserVouchersQueryHandler : IRequestHandler<GetUserVouchersQuery, IEnumerable<VoucherSummaryDto>>
{
    private readonly ICampaignRepository _campaignRepository;

    public GetUserVouchersQueryHandler(ICampaignRepository campaignRepository)
    {
        _campaignRepository = campaignRepository;
    }

    public async Task<IEnumerable<VoucherSummaryDto>> Handle(GetUserVouchersQuery request, CancellationToken cancellationToken)
    {
        var vouchers = await _campaignRepository.GetUserVouchersAsync(request.UserId);

        return vouchers.Select(v => new VoucherSummaryDto(
            v.Id, v.Code, v.RemainingValue,
            v.StatusId == 1 ? "Available" : v.StatusId == 2 ? "Claimed" : v.StatusId == 3 ? "PartiallyRedeemed" : v.StatusId == 4 ? "FullyRedeemed" : "Expired",
            v.ExpiresAt));
    }
}
