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.Application.IslamicFinance.Shariah;
using CashLineERP.Contracts.Documents;
using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;
using Microsoft.Extensions.DependencyInjection;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Murabaha_Asset_Evidence_Endpoints_Support_Attach_List_And_Detail()
    {
        await _client.AuthenticateAsInternalAsync();
        var assetId = SeedMurabahaAsset();

        var attachResponse = await _client.PostAsJsonAsync($"/api/v1/islamic-finance/murabaha-assets/{assetId}/evidence", new AttachIslamicFinanceMurabahaAssetEvidenceRequest
        {
            DocumentType = "PURCHASE_ORDER",
            AttachmentCategoryCode = "SUPPORTING_EVIDENCE",
            FileName = "murabaha-asset-evidence.pdf",
            StorageReference = $"murabaha/assets/{assetId}/evidence.pdf",
            StorageProviderCode = "LOCAL",
            ContentType = "application/pdf",
            FileSizeBytes = 1024,
            ChecksumText = "sha256:evidence"
        });

        Assert.Equal(HttpStatusCode.OK, attachResponse.StatusCode);
        var created = await attachResponse.Content.ReadFromJsonAsync<DocumentAttachmentResponse>();
        Assert.NotNull(created);
        Assert.Equal(assetId, created!.EntityId);

        var listResponse = await _client.GetAsync($"/api/v1/islamic-finance/murabaha-assets/{assetId}/evidence");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var list = await listResponse.Content.ReadFromJsonAsync<DocumentAttachmentResponse[]>();
        Assert.NotNull(list);
        Assert.Single(list!);

        var detailResponse = await _client.GetAsync($"/api/v1/islamic-finance/murabaha-assets/{assetId}/evidence/{created.DocumentLinkId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
    }

    [Fact]
    public async Task Murabaha_Asset_Evidence_Attach_Blocks_For_Unknown_Asset()
    {
        await _client.AuthenticateAsInternalAsync();

        var attachResponse = await _client.PostAsJsonAsync("/api/v1/islamic-finance/murabaha-assets/9999/evidence", new AttachIslamicFinanceMurabahaAssetEvidenceRequest
        {
            DocumentType = "PURCHASE_ORDER",
            AttachmentCategoryCode = "SUPPORTING_EVIDENCE",
            FileName = "murabaha-asset-evidence.pdf",
            StorageReference = "murabaha/assets/9999/evidence.pdf",
            StorageProviderCode = "LOCAL"
        });

        Assert.Equal(HttpStatusCode.BadRequest, attachResponse.StatusCode);
    }

    private long SeedMurabahaAsset()
    {
        using var scope = _factory.Services.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<CashLineErpDbContext>();

        var assetService = new IslamicFinanceMurabahaAssetService(new IslamicFinanceMurabahaAssetRepository(dbContext));
        var murabahaCase = CreateSubmittedMurabahaCase(dbContext);

        return assetService.CreateAsset(murabahaCase.Id, new CreateIslamicFinanceMurabahaAssetRequest
        {
            AssetDescription = "HTTP evidence asset",
            SupplierPartyId = 2,
            PurchaseReferenceNumber = $"PO-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            PurchaseCostAmount = 60000m
        }).Id;
    }

    private static IslamicFinanceMurabahaCaseResponse CreateSubmittedMurabahaCase(CashLineErpDbContext dbContext)
    {
        var partnerService = new IslamicFinancePartnerService(new IslamicFinancePartnerRepository(dbContext));
        var productService = new IslamicFinanceProductService(new IslamicFinanceProductRepository(dbContext));
        var facilityService = new IslamicFinanceFacilityService(new IslamicFinanceFacilityRepository(dbContext));
        var requestRepository = new IslamicFinanceRequestRepository(dbContext);
        var requestService = new IslamicFinanceRequestService(requestRepository);
        var shariahReviewService = new ShariahReviewService(new ShariahReviewRepository(dbContext));
        var murabahaService = new MurabahaCaseService(new MurabahaCaseRepository(dbContext));

        var partner = CreateActivePartner(partnerService);
        var product = CreateActiveProduct(productService);
        var facility = CreateActiveFacility(facilityService, partner.Id, product.Id);
        var request = CreateApprovedAssignedRequest(requestService, requestRepository, shariahReviewService, partner.Id, product.Id, facility.Id);

        var created = murabahaService.CreateCase(new CreateIslamicFinanceMurabahaCaseRequest
        {
            CaseNumber = $"MUR-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            FinancingRequestId = request.Id,
            CustomerPartyId = 1,
            PartnerLenderId = partner.Id,
            SupplierPartyId = 2,
            ProductProfileId = product.Id,
            TransactionCurrencyCode = "EGP",
            PurchaseCostAmount = 100000m,
            ProfitAmount = 20000m
        });

        return murabahaService.SubmitCase(created.Id, 3);
    }

    private static IslamicFinancePartnerLenderResponse CreateActivePartner(IslamicFinancePartnerService service)
    {
        var existing = service.GetPartnerLenders(activeOnly: true).FirstOrDefault(entry => entry.PartnerLenderPartyId == 1);
        if (existing is not null)
        {
            return existing;
        }

        var created = service.CreatePartnerLender(new CreateIslamicFinancePartnerLenderRequest
        {
            PartnerLenderPartyId = 1,
            DefaultCurrencyCode = "EGP",
            SupportsMurabaha = true,
            SupportsReceivablesFinance = false,
            SupportsTawarruq = false
        });

        service.SubmitPartnerLender(created.Id, 3);
        service.ApprovePartnerLender(created.Id, 4);
        return service.ActivatePartnerLender(created.Id, 4);
    }

    private static IslamicFinanceProductProfileResponse CreateActiveProduct(IslamicFinanceProductService service)
    {
        var created = service.CreateProductProfile(new CreateIslamicFinanceProductProfileRequest
        {
            ProductType = "MURABAHA",
            ProductCode = $"MUR-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            ProductName = "Murabaha Evidence HTTP Product",
            RequiresShariahReview = true,
            AllowsPartnerFunding = true,
            AllowsCashLineFunding = false
        });

        service.SubmitProductProfile(created.Id, 3);
        service.ApproveProductProfile(created.Id, 4);
        return service.ActivateProductProfile(created.Id, 4);
    }

    private static IslamicFinanceFacilityResponse CreateActiveFacility(
        IslamicFinanceFacilityService service,
        long partnerLenderId,
        long productProfileId)
    {
        var created = service.CreateFacility(new CreateIslamicFinanceFacilityRequest
        {
            PartnerLenderId = partnerLenderId,
            CustomerPartyId = 1,
            ProductProfileId = productProfileId,
            FacilityNumber = $"FAC-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 300000m,
            UtilizedAmount = 0m
        });

        service.SubmitFacility(created.Id, 3);
        service.ApproveFacility(created.Id, 4);
        return service.ActivateFacility(created.Id, 4);
    }

    private static IslamicFinanceFinancingRequestResponse CreateApprovedAssignedRequest(
        IslamicFinanceRequestService requestService,
        IslamicFinanceRequestRepository requestRepository,
        ShariahReviewService shariahReviewService,
        long partnerLenderId,
        long productProfileId,
        long facilityId)
    {
        var created = requestService.CreateRequest(new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = $"REQ-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            CustomerPartyId = 1,
            ProductProfileId = productProfileId,
            FacilityId = facilityId,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "SALES_ORDER",
            SourceDocumentId = 9601,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 120000m
        });

        requestService.SubmitRequest(created.Id, 3);
        requestService.ApproveRequest(created.Id, 4);

        var review = shariahReviewService.CreateReviewCase(new CreateIslamicFinanceShariahReviewRequest
        {
            ReviewCaseNumber = $"SHR-HTTPE-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            ProductProfileId = productProfileId,
            FinancingRequestId = created.Id,
            ReviewReasonCode = "SHARIAH_REVIEW"
        });
        shariahReviewService.SubmitReviewCase(review.Id, 3);
        shariahReviewService.RecommendOutcome(review.Id, new RecommendIslamicFinanceShariahOutcomeRequest
        {
            ReviewOutcomeCode = "APPROVED",
            ReviewNotes = "Approved for HTTP evidence attachment."
        }, 3);
        shariahReviewService.ApproveOutcome(review.Id, 4);

        requestService.AttachShariahReview(created.Id, new AttachIslamicFinanceShariahReviewRequest
        {
            ShariahReviewCaseId = review.Id
        }, 3);

        var assigned = requestRepository.AssignPartnerLender(created.Id, partnerLenderId, 3);
        return new IslamicFinanceFinancingRequestResponse
        {
            Id = assigned.FinancingRequestId,
            RequestNumber = assigned.RequestNumber,
            CustomerPartyId = assigned.CustomerPartyId,
            ProductProfileId = assigned.ProductProfileId,
            FacilityId = assigned.FacilityId,
            FundingSourceMode = assigned.FundingSourceMode,
            SourceDocumentType = assigned.SourceDocumentType,
            SourceDocumentId = assigned.SourceDocumentId,
            TransactionCurrencyCode = assigned.TransactionCurrencyCode,
            RequestedAmount = assigned.RequestedAmount,
            StatusCode = assigned.StatusCode,
            AssignedPartnerLenderId = assigned.AssignedPartnerLenderId,
            ShariahReviewCaseId = assigned.ShariahReviewCaseId
        };
    }
}
