using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class CardTokenReferenceService : ICardTokenReferenceService
{
    private readonly ICardTokenReferenceRepository _repository;

    public CardTokenReferenceService(ICardTokenReferenceRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<CardTokenReferenceResponse> GetCardTokenReferences(bool activeOnly = false, long? partyId = null, string? integrationProviderCode = null, string? usageCode = null) =>
        _repository.GetCardTokenReferences(activeOnly, partyId, integrationProviderCode, usageCode)
            .Select(Map)
            .ToArray();

    public CardTokenReferenceResponse? GetCardTokenReference(long cardTokenReferenceId)
    {
        var reference = _repository.GetCardTokenReference(cardTokenReferenceId);
        return reference is null ? null : Map(reference);
    }

    public CardTokenReferenceResponse CreateCardTokenReference(CreateCardTokenReferenceRequest request) =>
        Map(_repository.Create(new CreateCardTokenReferenceCommand(
            request.PartyId,
            request.PartyTypeCode,
            request.IntegrationProviderCode,
            request.UsageCode,
            request.CardBrandCode,
            request.MaskedPan,
            request.ExpiryMonth,
            request.ExpiryYear,
            request.TokenReference,
            request.ExternalCustomerReference,
            request.IsDefault,
            request.Notes)));

    public CardTokenReferenceResponse SubmitCardTokenReference(long cardTokenReferenceId, long actorUserId) =>
        Map(_repository.Submit(cardTokenReferenceId, actorUserId));

    public CardTokenReferenceResponse ApproveCardTokenReference(long cardTokenReferenceId, long actorUserId) =>
        Map(_repository.Approve(cardTokenReferenceId, actorUserId));

    public CardTokenReferenceResponse ActivateCardTokenReference(long cardTokenReferenceId, long actorUserId) =>
        Map(_repository.Activate(cardTokenReferenceId, actorUserId));

    public CardTokenReferenceResponse SuspendCardTokenReference(long cardTokenReferenceId, long actorUserId, SuspendCardTokenReferenceRequest request) =>
        Map(_repository.Suspend(cardTokenReferenceId, actorUserId, new SuspendCardTokenReferenceCommand(
            request.ReasonCode,
            request.Notes)));

    private static CardTokenReferenceResponse Map(CardTokenReferenceDetailView reference) =>
        new(
            reference.CardTokenReferenceId,
            reference.CardTokenReferenceNumber,
            reference.PartyId,
            reference.PartyTypeCode,
            reference.IntegrationProviderCode,
            reference.UsageCode,
            reference.CardBrandCode,
            reference.MaskedPan,
            reference.ExpiryMonth,
            reference.ExpiryYear,
            reference.TokenReference,
            reference.ExternalCustomerReference,
            reference.IsDefault,
            reference.StatusCode,
            reference.IsActive,
            reference.Notes,
            reference.SubmittedAtUtc,
            reference.SubmittedByUserId,
            reference.ApprovedAtUtc,
            reference.ApprovedByUserId,
            reference.ActivatedAtUtc,
            reference.ActivatedByUserId,
            reference.SuspendedAtUtc,
            reference.SuspendedByUserId,
            reference.SuspensionReasonCode,
            reference.SuspensionNotes);
}
