using CashLineERP.Application.IslamicFinance.Facilities;
using CashLineERP.Application.IslamicFinance.Murabaha;
using CashLineERP.Application.IslamicFinance.PartnerLenders;
using CashLineERP.Application.IslamicFinance.ProductProfiles;
using CashLineERP.Application.IslamicFinance.Requests;
using CashLineERP.Application.Reporting;
using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

namespace CashLineERP.Api.Tests;

public sealed class IslamicFinanceReportingServiceQaTests
{
    [Fact]
    public void Islamic_Finance_Pipeline_Report_Returns_Export_Ready_Read_Model()
    {
        using var dbContext = QaDbContextFactory.CreateContext();
        var seeded = SeedIslamicFinancePipeline(dbContext);

        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));

        var report = reportingService.GetIslamicFinancePipelineReport(null, null, seeded.PartnerLenderId);

        Assert.Equal(1, report.PartnerLenderCount);
        Assert.Equal(1, report.ActivePartnerLenderCount);
        Assert.Equal(1, report.FacilityCount);
        Assert.Equal(1, report.ActiveFacilityCount);
        Assert.Equal(1, report.FinancingRequestCount);
        Assert.Equal(1, report.ApprovedOrAssignedRequestCount);
        Assert.Equal(1, report.MurabahaCaseCount);
        Assert.Equal(1, report.ActiveMurabahaCaseCount);
        Assert.Equal(300000m, report.TotalFacilityLimitAmount);
        Assert.Equal(120000m, report.TotalRequestedAmount);
        Assert.Equal(120000m, report.TotalMurabahaSalePriceAmount);
        Assert.Contains(report.Rows, row => row.StageCode == "PARTNER");
        Assert.Contains(report.Rows, row => row.StageCode == "FACILITY");
        Assert.Contains(report.Rows, row => row.StageCode == "REQUEST");
        Assert.Contains(report.Rows, row => row.StageCode == "MURABAHA");

        var csv = reportingService.ExportIslamicFinancePipelineReportCsv(null, null, seeded.PartnerLenderId);
        Assert.Contains("ActivityDate,StageCode,RecordNumber,RecordId", csv);
        Assert.Contains(seeded.FacilityNumber, csv);
        Assert.Contains(seeded.RequestNumber, csv);
        Assert.Contains(seeded.CaseNumber, csv);
    }

    private static (long PartnerLenderId, string FacilityNumber, string RequestNumber, string CaseNumber) SeedIslamicFinancePipeline(CashLineErpDbContext dbContext)
    {
        var partnerService = new IslamicFinancePartnerService(new IslamicFinancePartnerRepository(dbContext));
        var productService = new IslamicFinanceProductService(new IslamicFinanceProductRepository(dbContext));
        var facilityService = new IslamicFinanceFacilityService(new IslamicFinanceFacilityRepository(dbContext));
        var requestService = new IslamicFinanceRequestService(new IslamicFinanceRequestRepository(dbContext));
        var murabahaService = new MurabahaCaseService(new MurabahaCaseRepository(dbContext));

        var partner = partnerService.CreatePartnerLender(new CreateIslamicFinancePartnerLenderRequest
        {
            PartnerLenderPartyId = 1,
            DefaultCurrencyCode = "EGP",
            SupportsMurabaha = true,
            SupportsReceivablesFinance = false,
            SupportsTawarruq = false
        });
        partnerService.SubmitPartnerLender(partner.Id, 3);
        partnerService.ApprovePartnerLender(partner.Id, 4);
        var activePartner = partnerService.ActivatePartnerLender(partner.Id, 4);

        var product = productService.CreateProductProfile(new CreateIslamicFinanceProductProfileRequest
        {
            ProductType = "MURABAHA",
            ProductCode = $"MUR-RPT-{Guid.NewGuid():N}"[..12].ToUpperInvariant(),
            ProductName = "Murabaha Reporting Product",
            RequiresShariahReview = false,
            AllowsPartnerFunding = true,
            AllowsCashLineFunding = false
        });
        productService.SubmitProductProfile(product.Id, 3);
        productService.ApproveProductProfile(product.Id, 4);
        var activeProduct = productService.ActivateProductProfile(product.Id, 4);

        var facilityNumber = $"FAC-RPT-{Guid.NewGuid():N}"[..12].ToUpperInvariant();
        var facility = facilityService.CreateFacility(new CreateIslamicFinanceFacilityRequest
        {
            PartnerLenderId = activePartner.Id,
            CustomerPartyId = 2,
            ProductProfileId = activeProduct.Id,
            FacilityNumber = facilityNumber,
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 300000m,
            UtilizedAmount = 25000m
        });
        facilityService.SubmitFacility(facility.Id, 3);
        facilityService.ApproveFacility(facility.Id, 4);
        var activeFacility = facilityService.ActivateFacility(facility.Id, 4);

        var requestNumber = $"REQ-RPT-{Guid.NewGuid():N}"[..12].ToUpperInvariant();
        var request = requestService.CreateRequest(new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = requestNumber,
            CustomerPartyId = 2,
            ProductProfileId = activeProduct.Id,
            FacilityId = activeFacility.Id,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "SALES_ORDER",
            SourceDocumentId = 61001,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 120000m
        });
        requestService.SubmitRequest(request.Id, 3);
        requestService.ApproveRequest(request.Id, 4);
        var assignedRequest = requestService.AssignPartnerLender(request.Id, new AssignIslamicFinancePartnerLenderRequest
        {
            PartnerLenderId = activePartner.Id
        }, 5);

        var caseNumber = $"MUR-RPT-{Guid.NewGuid():N}"[..12].ToUpperInvariant();
        var murabahaCase = murabahaService.CreateCase(new CreateIslamicFinanceMurabahaCaseRequest
        {
            CaseNumber = caseNumber,
            FinancingRequestId = assignedRequest.Id,
            CustomerPartyId = 2,
            PartnerLenderId = activePartner.Id,
            SupplierPartyId = 1,
            ProductProfileId = activeProduct.Id,
            TransactionCurrencyCode = "EGP",
            PurchaseCostAmount = 100000m,
            ProfitAmount = 20000m
        });
        murabahaService.SubmitCase(murabahaCase.Id, 3);
        murabahaService.ApproveCase(murabahaCase.Id, 4);
        murabahaService.ActivateCase(murabahaCase.Id, 4);

        return (activePartner.Id, facilityNumber, requestNumber, caseNumber);
    }
}
