using MediatR;
using TakeoutSaaS.Application.App.Members.PointsMall.Commands;
using TakeoutSaaS.Application.App.Members.PointsMall.Dto;
using TakeoutSaaS.Domain.Membership.Enums;
using TakeoutSaaS.Domain.Membership.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Members.PointsMall.Handlers;

/// <summary>
/// 核销积分商城兑换记录处理器。
/// </summary>
public sealed class VerifyPointMallRecordCommandHandler(
    IPointMallRepository repository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor currentUserAccessor)
    : IRequestHandler<VerifyPointMallRecordCommand, MemberPointMallRecordDetailDto>
{
    /// <inheritdoc />
    public async Task<MemberPointMallRecordDetailDto> Handle(
        VerifyPointMallRecordCommand request,
        CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var verifyMethod = MemberPointMallMapping.ParseVerifyMethod(request.VerifyMethod);
        var verifyRemark = MemberPointMallMapping.NormalizeRemark(request.VerifyRemark, "verifyRemark");

        var record = await repository.FindRecordByIdAsync(
            tenantId,
            request.StoreId,
            request.RecordId,
            cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "兑换记录不存在");

        if (record.Status != MemberPointMallRecordStatus.PendingPickup)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "当前状态不可核销");
        }

        var nowUtc = DateTime.UtcNow;
        record.Status = MemberPointMallRecordStatus.Completed;
        record.IssuedAt ??= nowUtc;
        record.VerifiedAt = nowUtc;
        record.VerifyMethod = verifyMethod;
        record.VerifyRemark = verifyRemark;
        record.VerifiedBy = currentUserAccessor.IsAuthenticated && currentUserAccessor.UserId > 0
            ? currentUserAccessor.UserId
            : null;

        await repository.UpdateRecordAsync(record, cancellationToken);
        await repository.SaveChangesAsync(cancellationToken);

        return MemberPointMallDtoFactory.ToRecordDetailDto(record);
    }
}
