using System.Net;
using System.Net.Http.Json;
using CashLineERP.Application.Finance;
using CashLineERP.Application.IslamicFinance.Facilities;
using CashLineERP.Application.IslamicFinance.PartnerLenders;
using CashLineERP.Application.IslamicFinance.ProductProfiles;
using CashLineERP.Application.IslamicFinance.Requests;
using CashLineERP.Contracts.Parties;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

namespace CashLineERP.Api.Tests;

internal static class IslamicFinanceReceivablesFinanceSeedHelper
{
    internal sealed record SeedResult(
        long PartnerId,
        long ProductId,
        long FacilityId,
        long RequestId,
        long InvoiceId,
        decimal OutstandingAmount);

    public static SeedResult SeedServiceScenario(CashLineErpDbContext dbContext, string prefix)
    {
        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 invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));

        var token = Guid.NewGuid().ToString("N")[..6].ToUpperInvariant();
        var runPrefix = $"{prefix}-{token}";

        var partner = CreateActivePartner(partnerService, runPrefix);
        var product = CreateActiveProduct(productService, runPrefix);
        var facility = CreateActiveFacility(facilityService, partner.Id, product.Id, runPrefix);
        var postedInvoice = CreatePostedInvoice(invoiceService, runPrefix);

        var request = requestService.CreateRequest(new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = $"{runPrefix}-REQ",
            CustomerPartyId = 2,
            ProductProfileId = product.Id,
            FacilityId = facility.Id,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "AR_INVOICE",
            SourceDocumentId = postedInvoice.AccountsReceivableInvoiceId,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 80m
        });
        requestService.SubmitRequest(request.Id, 10);
        requestService.ApproveRequest(request.Id, 11);
        requestRepository.AssignPartnerLender(request.Id, partner.Id, 10);

        return new SeedResult(
            partner.Id,
            product.Id,
            facility.Id,
            request.Id,
            postedInvoice.AccountsReceivableInvoiceId,
            postedInvoice.TotalAmount);
    }

    public static async Task<SeedResult> SeedHttpScenarioAsync(HttpClient client, string prefix)
    {
        var token = Guid.NewGuid().ToString("N")[..6].ToUpperInvariant();
        var runPrefix = $"{prefix}-{token}";

        await client.AuthenticateAsFinanceMakerAsync();
        var invoice = await ReadOkAsync<AccountsReceivableInvoiceResponse>(await client.PostAsJsonAsync("/api/v1/finance/ar-invoices", new CreateAccountsReceivableInvoiceRequest(
            CustomerId: 2,
            SalesOrderId: 1,
            DispatchOrderId: 1,
            InvoiceType: "TAX",
            InvoiceDate: new DateOnly(2026, 4, 8),
            TaxDate: new DateOnly(2026, 4, 8),
            DueDate: new DateOnly(2026, 4, 15),
            CurrencyCode: "EGP",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 100m, "VAT14")
            ])));
        await EnsureOkAsync(await client.PostAsync($"/api/v1/finance/ar-invoices/{invoice.AccountsReceivableInvoiceId}/submit", null));

        await client.AuthenticateAsFinanceCheckerAsync();
        await EnsureOkAsync(await client.PostAsync($"/api/v1/finance/ar-invoices/{invoice.AccountsReceivableInvoiceId}/approve", null));
        var postedInvoice = await ReadOkAsync<AccountsReceivableInvoiceResponse>(await client.PostAsync($"/api/v1/finance/ar-invoices/{invoice.AccountsReceivableInvoiceId}/post", null));

        await client.AuthenticateAsInternalAsync();
        var partnerMobile = $"+2010{Random.Shared.Next(10000000, 99999999)}";
        var partnerParty = await ReadOkAsync<BusinessPartyResponse>(await client.PostAsJsonAsync("/api/v1/parties", new CreateBusinessPartyRequest(
            PartyCode: $"{runPrefix}-PL",
            PartyName: $"{runPrefix} Partner Lender",
            PartyType: "PARTNER_LENDER",
            CountryCode: "EG",
            FirmNationalId: null,
            TaxRegistrationNumber: null,
            TaxBranchCode: null,
            Email: $"{runPrefix.ToLowerInvariant()}@partner.local",
            MobileNumber: partnerMobile,
            AddressLine1: "Cairo",
            CreditLimitAmount: null,
            CreditTermsDays: null,
            IsCreditHoldEnabled: false,
            CreditHoldReason: null)));

        await client.AuthenticateAsInternalAsync();
        var partner = await ReadOkAsync<IslamicFinancePartnerLenderResponse>(await client.PostAsJsonAsync("/api/v1/islamic-finance/partners", new CreateIslamicFinancePartnerLenderRequest
        {
            PartnerLenderPartyId = partnerParty.PartyId,
            DefaultCurrencyCode = "EGP",
            SupportsMurabaha = false,
            SupportsReceivablesFinance = true,
            SupportsTawarruq = false
        }));
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/partners/{partner.Id}/submit", null));

        await client.AuthenticateAsFinanceCheckerAsync();
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/partners/{partner.Id}/approve", null));
        var activatedPartner = await ReadOkAsync<IslamicFinancePartnerLenderResponse>(await client.PostAsync($"/api/v1/islamic-finance/partners/{partner.Id}/activate", null));

        await client.AuthenticateAsInternalAsync();
        var product = await ReadOkAsync<IslamicFinanceProductProfileResponse>(await client.PostAsJsonAsync("/api/v1/islamic-finance/product-profiles", new CreateIslamicFinanceProductProfileRequest
        {
            ProductType = "RECEIVABLES_FINANCE",
            ProductCode = $"{runPrefix}-PROD",
            ProductName = $"{runPrefix} Receivables Finance",
            RequiresShariahReview = false,
            AllowsPartnerFunding = true,
            AllowsCashLineFunding = false
        }));
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/product-profiles/{product.Id}/submit", null));

        await client.AuthenticateAsFinanceCheckerAsync();
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/product-profiles/{product.Id}/approve", null));
        var activatedProduct = await ReadOkAsync<IslamicFinanceProductProfileResponse>(await client.PostAsync($"/api/v1/islamic-finance/product-profiles/{product.Id}/activate", null));

        await client.AuthenticateAsInternalAsync();
        var facility = await ReadOkAsync<IslamicFinanceFacilityResponse>(await client.PostAsJsonAsync("/api/v1/islamic-finance/facilities", new CreateIslamicFinanceFacilityRequest
        {
            PartnerLenderId = activatedPartner.Id,
            CustomerPartyId = 2,
            ProductProfileId = activatedProduct.Id,
            FacilityNumber = $"{runPrefix}-FAC",
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 250000m
        }));
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/facilities/{facility.Id}/submit", null));

        await client.AuthenticateAsFinanceCheckerAsync();
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/facilities/{facility.Id}/approve", null));
        var activatedFacility = await ReadOkAsync<IslamicFinanceFacilityResponse>(await client.PostAsync($"/api/v1/islamic-finance/facilities/{facility.Id}/activate", null));

        await client.AuthenticateAsInternalAsync();
        var request = await ReadOkAsync<IslamicFinanceFinancingRequestResponse>(await client.PostAsJsonAsync("/api/v1/islamic-finance/requests", new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = $"{runPrefix}-REQ",
            CustomerPartyId = 2,
            ProductProfileId = activatedProduct.Id,
            FacilityId = activatedFacility.Id,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "AR_INVOICE",
            SourceDocumentId = postedInvoice.AccountsReceivableInvoiceId,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 80m
        }));
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/requests/{request.Id}/submit", null));

        await client.AuthenticateAsFinanceCheckerAsync();
        await EnsureOkAsync(await client.PostAsync($"/api/v1/islamic-finance/requests/{request.Id}/approve", null));

        await client.AuthenticateAsInternalAsync();
        await EnsureOkAsync(await client.PostAsJsonAsync($"/api/v1/islamic-finance/requests/{request.Id}/assign-partner-lender", new AssignIslamicFinancePartnerLenderRequest
        {
            PartnerLenderId = activatedPartner.Id
        }));

        return new SeedResult(
            activatedPartner.Id,
            activatedProduct.Id,
            activatedFacility.Id,
            request.Id,
            postedInvoice.AccountsReceivableInvoiceId,
            postedInvoice.TotalAmount);
    }

    private static IslamicFinancePartnerLenderResponse CreateActivePartner(IslamicFinancePartnerService partnerService, string prefix)
    {
        var created = partnerService.CreatePartnerLender(new CreateIslamicFinancePartnerLenderRequest
        {
            PartnerLenderPartyId = 1,
            DefaultCurrencyCode = "EGP",
            SupportsMurabaha = false,
            SupportsReceivablesFinance = true,
            SupportsTawarruq = false
        });

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

    private static IslamicFinanceProductProfileResponse CreateActiveProduct(IslamicFinanceProductService productService, string prefix)
    {
        var created = productService.CreateProductProfile(new CreateIslamicFinanceProductProfileRequest
        {
            ProductType = "RECEIVABLES_FINANCE",
            ProductCode = $"{prefix}-PROD",
            ProductName = $"{prefix} Receivables Finance",
            RequiresShariahReview = false,
            AllowsPartnerFunding = true,
            AllowsCashLineFunding = false
        });

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

    private static IslamicFinanceFacilityResponse CreateActiveFacility(
        IslamicFinanceFacilityService facilityService,
        long partnerId,
        long productId,
        string prefix)
    {
        var created = facilityService.CreateFacility(new CreateIslamicFinanceFacilityRequest
        {
            PartnerLenderId = partnerId,
            CustomerPartyId = 2,
            ProductProfileId = productId,
            FacilityNumber = $"{prefix}-FAC",
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 250000m,
            UtilizedAmount = 0m
        });

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

    private static AccountsReceivableInvoiceResponse CreatePostedInvoice(IAccountsReceivableInvoiceService invoiceService, string prefix)
    {
        var created = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
            CustomerId: 2,
            SalesOrderId: 1,
            DispatchOrderId: 1,
            InvoiceType: "TAX",
            InvoiceDate: new DateOnly(2026, 4, 8),
            TaxDate: new DateOnly(2026, 4, 8),
            DueDate: new DateOnly(2026, 4, 15),
            CurrencyCode: "EGP",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 100m, "VAT14")
            ]));

        return AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(invoiceService, created.AccountsReceivableInvoiceId);
    }

    private static async Task<T> ReadOkAsync<T>(HttpResponseMessage response)
    {
        if (response.StatusCode != HttpStatusCode.OK)
        {
            throw new InvalidOperationException(await response.Content.ReadAsStringAsync());
        }

        return await response.Content.ReadFromJsonAsync<T>() ?? throw new InvalidOperationException();
    }

    private static async Task EnsureOkAsync(HttpResponseMessage response)
    {
        if (response.StatusCode != HttpStatusCode.OK)
        {
            throw new InvalidOperationException(await response.Content.ReadAsStringAsync());
        }
    }
}
