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

namespace CashLineERP.Application.IslamicFinance.ReceivablesFinance;

public sealed class ReceivablesFinanceService : IReceivablesFinanceService
{
    private readonly IReceivablesFinanceRepository _repository;

    public ReceivablesFinanceService(IReceivablesFinanceRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<IslamicFinanceReceivablesCaseResponse> GetCases(
        string? statusCode = null,
        long? customerPartyId = null,
        long? partnerLenderId = null) =>
        _repository.GetCases(statusCode, customerPartyId, partnerLenderId).Select(Map).ToArray();

    public IslamicFinanceReceivablesCaseResponse? GetCase(long receivablesCaseId)
    {
        var entry = _repository.GetCase(receivablesCaseId);
        return entry is null ? null : Map(entry);
    }

    public IslamicFinanceReceivablesCaseResponse CreateCase(CreateIslamicFinanceReceivablesCaseRequest request) =>
        Map(_repository.Create(new CreateIslamicFinanceReceivablesCaseCommand(
            request.CaseNumber,
            request.FinancingRequestId,
            request.Lines.Select(line => new CreateIslamicFinanceReceivablesCaseLineCommand(
                line.AccountsReceivableInvoiceId,
                line.FinancedAmount)).ToArray())));

    public IslamicFinanceReceivablesCaseResponse SubmitCase(long receivablesCaseId, long actorUserId) =>
        Map(_repository.Submit(receivablesCaseId, actorUserId));

    public IslamicFinanceReceivablesCaseResponse ApproveCase(long receivablesCaseId, long actorUserId) =>
        Map(_repository.Approve(receivablesCaseId, actorUserId));

    public IslamicFinanceReceivablesCaseResponse ActivateCase(long receivablesCaseId, long actorUserId) =>
        Map(_repository.Activate(receivablesCaseId, actorUserId));

    public IReadOnlyCollection<IslamicFinanceLifecycleHistoryEntryResponse> GetCaseHistory(long receivablesCaseId) =>
        _repository.GetCaseHistory(receivablesCaseId).Select(Map).ToArray();

    public IslamicFinanceReceivablesCaseAuditResponse? GetCaseAudit(long receivablesCaseId)
    {
        var entry = _repository.GetCaseAudit(receivablesCaseId);
        return entry is null ? null : new IslamicFinanceReceivablesCaseAuditResponse(
            Map(entry.ReceivablesCase),
            entry.Events.Select(Map).ToArray());
    }

    public IReadOnlyCollection<IslamicFinanceReceivablesEligibilityInvoiceResponse> GetEligibleInvoices(long customerPartyId, string? currencyCode, DateOnly? asOfDate = null) =>
        _repository.GetEligibleInvoices(customerPartyId, currencyCode, asOfDate ?? DateOnly.FromDateTime(DateTime.UtcNow))
            .Select(Map)
            .ToArray();

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

    private static IslamicFinanceReceivablesEligibilityInvoiceResponse Map(IslamicFinanceReceivablesEligibilityInvoiceView entry) =>
        new()
        {
            AccountsReceivableInvoiceId = entry.AccountsReceivableInvoiceId,
            InvoiceNumber = entry.InvoiceNumber,
            CustomerId = entry.CustomerId,
            SalesOrderId = entry.SalesOrderId,
            DispatchOrderId = entry.DispatchOrderId,
            InvoiceDate = entry.InvoiceDate,
            DueDate = entry.DueDate,
            CurrencyCode = entry.CurrencyCode,
            TotalAmount = entry.TotalAmount,
            OutstandingAmount = entry.OutstandingAmount,
            OverdueDays = entry.OverdueDays,
            IsAlreadyLinked = entry.IsAlreadyLinked
        };

    private static IslamicFinanceReceivablesCaseResponse Map(IslamicFinanceReceivablesCaseDetailView entry) =>
        new()
        {
            Id = entry.ReceivablesCaseId,
            CaseNumber = entry.CaseNumber,
            FinancingRequestId = entry.FinancingRequestId,
            CustomerPartyId = entry.CustomerPartyId,
            PartnerLenderId = entry.PartnerLenderId,
            FacilityId = entry.FacilityId,
            ProductProfileId = entry.ProductProfileId,
            TransactionCurrencyCode = entry.TransactionCurrencyCode,
            TotalReceivableAmount = entry.TotalReceivableAmount,
            FinancedAmount = entry.FinancedAmount,
            AdvanceRatePercent = entry.AdvanceRatePercent,
            StatusCode = entry.StatusCode,
            WorkflowInstanceId = entry.WorkflowInstanceId,
            CreatedAtUtc = entry.CreatedAtUtc,
            CreatedByUserId = entry.CreatedByUserId,
            SubmittedAtUtc = entry.SubmittedAtUtc,
            SubmittedByUserId = entry.SubmittedByUserId,
            ApprovedAtUtc = entry.ApprovedAtUtc,
            ApprovedByUserId = entry.ApprovedByUserId,
            ActivatedAtUtc = entry.ActivatedAtUtc,
            ActivatedByUserId = entry.ActivatedByUserId,
            UpdatedAtUtc = entry.UpdatedAtUtc,
            UpdatedByUserId = entry.UpdatedByUserId,
            Lines = entry.Lines.Select(line => new IslamicFinanceReceivablesCaseLineResponse
            {
                Id = line.ReceivablesCaseLineId,
                ReceivablesCaseId = line.ReceivablesCaseId,
                AccountsReceivableInvoiceId = line.AccountsReceivableInvoiceId,
                InvoiceNumber = line.InvoiceNumber,
                InvoiceDate = line.InvoiceDate,
                DueDate = line.DueDate,
                ReceivableAmount = line.ReceivableAmount,
                FinancedAmount = line.FinancedAmount,
                StatusCode = line.StatusCode,
                CreatedAtUtc = line.CreatedAtUtc,
                CreatedByUserId = line.CreatedByUserId,
                UpdatedAtUtc = line.UpdatedAtUtc,
                UpdatedByUserId = line.UpdatedByUserId
            }).ToArray()
        };
}
