using System.Net;
using System.Net.Http.Json;
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.Contracts.IslamicFinance;
using CashLineERP.Contracts.Reporting;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;
using Microsoft.Extensions.DependencyInjection;

namespace CashLineERP.Api.Tests;

public sealed class IslamicFinanceReportingQaTests : IClassFixture<ApiTestFactory>
{
    private readonly HttpClient _client;
    private readonly ApiTestFactory _factory;

    public IslamicFinanceReportingQaTests(ApiTestFactory factory)
    {
        _factory = factory;
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Islamic_Finance_Pipeline_Report_Endpoints_Return_Read_Model_And_Csv_Export()
    {
        await _client.AuthenticateAsInternalAsync();
        var seeded = SeedIslamicFinancePipeline();

        var reportResponse = await _client.GetAsync($"/api/v1/reports/islamic-finance/pipeline?partnerLenderId={seeded.PartnerLenderId}");
        Assert.Equal(HttpStatusCode.OK, reportResponse.StatusCode);
        var report = await reportResponse.Content.ReadFromJsonAsync<IslamicFinancePipelineReportResponse>();
        Assert.NotNull(report);
        Assert.Equal(1, report!.PartnerLenderCount);
        Assert.Contains(report.Rows, row => row.StageCode == "MURABAHA" && row.RecordNumber == seeded.CaseNumber);

        var exportResponse = await _client.GetAsync($"/api/v1/reports/islamic-finance/pipeline/export?partnerLenderId={seeded.PartnerLenderId}");
        Assert.Equal(HttpStatusCode.OK, exportResponse.StatusCode);
        Assert.Equal("text/csv", exportResponse.Content.Headers.ContentType?.MediaType);
        var csv = await exportResponse.Content.ReadAsStringAsync();
        Assert.Contains("ActivityDate,StageCode,RecordNumber,RecordId", csv);
        Assert.Contains(seeded.RequestNumber, csv);
        Assert.Contains(seeded.CaseNumber, csv);
    }

    private (long PartnerLenderId, string RequestNumber, string CaseNumber) SeedIslamicFinancePipeline()
    {
        using var scope = _factory.Services.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<CashLineErpDbContext>();

        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-RPH-{Guid.NewGuid():N}"[..12].ToUpperInvariant(),
            ProductName = "Murabaha Reporting HTTP 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 facility = facilityService.CreateFacility(new CreateIslamicFinanceFacilityRequest
        {
            PartnerLenderId = activePartner.Id,
            CustomerPartyId = 2,
            ProductProfileId = activeProduct.Id,
            FacilityNumber = $"FAC-RPH-{Guid.NewGuid():N}"[..12].ToUpperInvariant(),
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 300000m,
            UtilizedAmount = 15000m
        });
        facilityService.SubmitFacility(facility.Id, 3);
        facilityService.ApproveFacility(facility.Id, 4);
        var activeFacility = facilityService.ActivateFacility(facility.Id, 4);

        var requestNumber = $"REQ-RPH-{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 = 62001,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 125000m
        });
        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-RPH-{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 = 25000m
        });
        murabahaService.SubmitCase(murabahaCase.Id, 3);
        murabahaService.ApproveCase(murabahaCase.Id, 4);
        murabahaService.ActivateCase(murabahaCase.Id, 4);

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