using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Application.IslamicFinance;
using CashLineERP.SharedKernel.IslamicFinance;

namespace CashLineERP.Application.IslamicFinance.Disbursements;

public sealed class IslamicFinanceMurabahaDisbursementService : IIslamicFinanceMurabahaDisbursementService
{
    private readonly IIslamicFinanceMurabahaDisbursementRepository _repository;

    public IslamicFinanceMurabahaDisbursementService(IIslamicFinanceMurabahaDisbursementRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<IslamicFinanceMurabahaDisbursementResponse> GetDisbursements(
        long? murabahaCaseId = null,
        string? statusCode = null,
        string? targetType = null) =>
        _repository.GetDisbursements(murabahaCaseId, statusCode, targetType).Select(Map).ToArray();

    public IslamicFinanceMurabahaDisbursementResponse? GetDisbursement(long disbursementId)
    {
        var entry = _repository.GetDisbursement(disbursementId);
        return entry is null ? null : Map(entry);
    }

    public IslamicFinanceMurabahaDisbursementResponse CreateDisbursement(CreateIslamicFinanceMurabahaDisbursementRequest request) =>
        Map(_repository.Create(new CreateIslamicFinanceMurabahaDisbursementCommand(
            request.MurabahaCaseId,
            request.DisbursementNumber,
            request.SupplierPartyId,
            IslamicFinanceDisbursementCatalog.ParseTargetType(request.TargetType),
            request.InstructedAmount,
            request.PlannedExecutionDate)));

    public IslamicFinanceMurabahaDisbursementResponse SubmitDisbursement(long disbursementId, long actorUserId) =>
        Map(_repository.Submit(disbursementId, actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse ApproveDisbursement(long disbursementId, long actorUserId) =>
        Map(_repository.Approve(disbursementId, actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse ReturnDisbursement(long disbursementId, long actorUserId) =>
        Map(_repository.Return(disbursementId, actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse RejectDisbursement(long disbursementId, long actorUserId) =>
        Map(_repository.Reject(disbursementId, actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse ExecuteDisbursement(long disbursementId, ExecuteIslamicFinanceMurabahaDisbursementRequest request, long actorUserId) =>
        Map(_repository.Execute(disbursementId, new ExecuteIslamicFinanceMurabahaDisbursementCommand(
            request.ExecutionReferenceNumber,
            request.ExecutedAtUtc,
            request.ExecutedAmount,
            request.ExecutionNotes), actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse SuspendDisbursement(long disbursementId, SuspendIslamicFinanceMurabahaDisbursementRequest request, long actorUserId) =>
        Map(_repository.Suspend(disbursementId, request.ReasonCode, actorUserId));

    public IslamicFinanceMurabahaDisbursementResponse CloseDisbursement(long disbursementId, long actorUserId) =>
        Map(_repository.Close(disbursementId, actorUserId));

    public IReadOnlyCollection<IslamicFinanceLifecycleHistoryEntryResponse> GetDisbursementHistory(long disbursementId) =>
        _repository.GetDisbursementHistory(disbursementId).Select(Map).ToArray();

    public IslamicFinanceMurabahaDisbursementAuditResponse? GetDisbursementAudit(long disbursementId)
    {
        var entry = _repository.GetDisbursementAudit(disbursementId);
        return entry is null ? null : new IslamicFinanceMurabahaDisbursementAuditResponse(
            Map(entry.Disbursement),
            entry.Events.Select(Map).ToArray());
    }

    private static IslamicFinanceMurabahaDisbursementResponse Map(IslamicFinanceMurabahaDisbursementDetailView entry) =>
        new()
        {
            Id = entry.DisbursementId,
            DisbursementNumber = entry.DisbursementNumber,
            MurabahaCaseId = entry.MurabahaCaseId,
            CustomerPartyId = entry.CustomerPartyId,
            PartnerLenderId = entry.PartnerLenderId,
            SupplierPartyId = entry.SupplierPartyId,
            FundingSourceMode = entry.FundingSourceMode,
            TargetType = entry.TargetType,
            TransactionCurrencyCode = entry.TransactionCurrencyCode,
            InstructedAmount = entry.InstructedAmount,
            ExecutedAmount = entry.ExecutedAmount,
            OutstandingAmount = entry.OutstandingAmount,
            PlannedExecutionDate = entry.PlannedExecutionDate,
            StatusCode = entry.StatusCode,
            WorkflowInstanceId = entry.WorkflowInstanceId,
            CreatedAtUtc = entry.CreatedAtUtc,
            CreatedByUserId = entry.CreatedByUserId,
            SubmittedAtUtc = entry.SubmittedAtUtc,
            SubmittedByUserId = entry.SubmittedByUserId,
            ApprovedAtUtc = entry.ApprovedAtUtc,
            ApprovedByUserId = entry.ApprovedByUserId,
            ExecutedAtUtc = entry.ExecutedAtUtc,
            ExecutedByUserId = entry.ExecutedByUserId,
            ExecutionReferenceNumber = entry.ExecutionReferenceNumber,
            ExecutionNotes = entry.ExecutionNotes,
            SuspendedAtUtc = entry.SuspendedAtUtc,
            SuspendedByUserId = entry.SuspendedByUserId,
            SuspensionReasonCode = entry.SuspensionReasonCode,
            UpdatedAtUtc = entry.UpdatedAtUtc,
            UpdatedByUserId = entry.UpdatedByUserId
        };

    private static IslamicFinanceLifecycleHistoryEntryResponse Map(IslamicFinanceLifecycleHistoryEntryView entry) =>
        new(
            entry.EntityId,
            entry.EventCode,
            entry.SourceType,
            entry.SourceId,
            entry.ActorUserId,
            entry.Notes,
            entry.OccurredAtUtc);
}
