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

namespace CashLineERP.Application.IslamicFinance.Murabaha;

public sealed class MurabahaCaseService : IMurabahaCaseService
{
    private readonly IMurabahaCaseRepository _repository;

    public MurabahaCaseService(IMurabahaCaseRepository repository)
    {
        _repository = repository;
    }

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

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

    public IslamicFinanceMurabahaCaseResponse CreateCase(CreateIslamicFinanceMurabahaCaseRequest request) =>
        Map(_repository.Create(new CreateIslamicFinanceMurabahaCaseCommand(
            request.CaseNumber,
            request.FinancingRequestId,
            request.CustomerPartyId,
            request.PartnerLenderId,
            request.SupplierPartyId,
            request.ProductProfileId,
            request.ContractTemplateId,
            request.TransactionCurrencyCode,
            request.PurchaseCostAmount,
            request.ProfitAmount)));

    public IslamicFinanceMurabahaCaseResponse SubmitCase(long murabahaCaseId, long actorUserId) =>
        Map(_repository.Submit(murabahaCaseId, actorUserId));

    public IslamicFinanceMurabahaCaseResponse ApproveCase(long murabahaCaseId, long actorUserId) =>
        Map(_repository.Approve(murabahaCaseId, actorUserId));

    public IslamicFinanceMurabahaCaseResponse ActivateCase(long murabahaCaseId, long actorUserId) =>
        Map(_repository.Activate(murabahaCaseId, actorUserId));

    public IslamicFinanceMurabahaScheduleResponse GenerateSchedule(
        long murabahaCaseId,
        long actorUserId,
        GenerateIslamicFinanceMurabahaScheduleRequest request) =>
        Map(_repository.GenerateSchedule(
            murabahaCaseId,
            actorUserId,
            new GenerateIslamicFinanceMurabahaScheduleCommand(
                request.InstallmentCount,
                request.FirstDueDate,
                request.InstallmentIntervalMonths)));

    public IslamicFinanceMurabahaScheduleResponse? GetSchedule(long murabahaCaseId)
    {
        var schedule = _repository.GetSchedule(murabahaCaseId);
        return schedule is null ? null : Map(schedule);
    }

    public IslamicFinanceMurabahaScheduleLineResponse? GetScheduleInstallment(long murabahaCaseId, int installmentNumber)
    {
        var line = _repository.GetScheduleInstallment(murabahaCaseId, installmentNumber);
        return line is null ? null : Map(line);
    }

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

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

    private static IslamicFinanceMurabahaScheduleResponse Map(IslamicFinanceMurabahaScheduleView entry) =>
        new()
        {
            MurabahaCaseId = entry.MurabahaCaseId,
            CaseNumber = entry.CaseNumber,
            FinancingRequestId = entry.FinancingRequestId,
            CustomerPartyId = entry.CustomerPartyId,
            PartnerLenderId = entry.PartnerLenderId,
            TransactionCurrencyCode = entry.TransactionCurrencyCode,
            PurchaseCostAmount = entry.PurchaseCostAmount,
            ProfitAmount = entry.ProfitAmount,
            SalePriceAmount = entry.SalePriceAmount,
            StatusCode = entry.StatusCode,
            InstallmentCount = entry.Lines.Count,
            Lines = entry.Lines.Select(Map).ToArray()
        };

    private static IslamicFinanceMurabahaScheduleLineResponse Map(IslamicFinanceMurabahaScheduleLineView entry) =>
        new()
        {
            MurabahaCaseId = entry.MurabahaCaseId,
            InstallmentNumber = entry.InstallmentNumber,
            DueDate = entry.DueDate,
            PrincipalAmount = entry.PrincipalAmount,
            ProfitAmount = entry.ProfitAmount,
            InstallmentAmount = entry.InstallmentAmount,
            OutstandingBalanceAmount = entry.OutstandingBalanceAmount,
            StatusCode = entry.StatusCode
        };

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

    private static IslamicFinanceMurabahaCaseResponse Map(IslamicFinanceMurabahaCaseDetailView entry) =>
        new()
        {
            Id = entry.MurabahaCaseId,
            CaseNumber = entry.CaseNumber,
            FinancingRequestId = entry.FinancingRequestId,
            CustomerPartyId = entry.CustomerPartyId,
            PartnerLenderId = entry.PartnerLenderId,
            SupplierPartyId = entry.SupplierPartyId,
            ProductProfileId = entry.ProductProfileId,
            ContractTemplateId = entry.ContractTemplateId,
            TransactionCurrencyCode = entry.TransactionCurrencyCode,
            PurchaseCostAmount = entry.PurchaseCostAmount,
            ProfitAmount = entry.ProfitAmount,
            SalePriceAmount = entry.SalePriceAmount,
            StatusCode = entry.StatusCode,
            WorkflowInstanceId = entry.WorkflowInstanceId,
            SubmittedAtUtc = entry.SubmittedAtUtc,
            SubmittedByUserId = entry.SubmittedByUserId,
            ApprovedAtUtc = entry.ApprovedAtUtc,
            ApprovedByUserId = entry.ApprovedByUserId,
            ActivatedAtUtc = entry.ActivatedAtUtc,
            ActivatedByUserId = entry.ActivatedByUserId
        };
}
