using CashLineERP.Application.Documents;
using CashLineERP.Application.IslamicFinance.ContractTemplates;
using CashLineERP.Application.IslamicFinance.Disbursements;
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.IslamicFinance;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

namespace CashLineERP.Api.Tests;

internal static class IslamicFinanceIntegrationTestSeeder
{
    public static IslamicFinanceIntegrationSeedResult SeedOperationalLifecycle(CashLineErpDbContext dbContext)
    {
        var partnerService = new IslamicFinancePartnerService(new IslamicFinancePartnerRepository(dbContext));
        var productService = new IslamicFinanceProductService(new IslamicFinanceProductRepository(dbContext));
        var facilityService = new IslamicFinanceFacilityService(new IslamicFinanceFacilityRepository(dbContext));
        var templateService = new IslamicFinanceContractTemplateService(new IslamicFinanceContractTemplateRepository(dbContext));
        var requestService = new IslamicFinanceRequestService(new IslamicFinanceRequestRepository(dbContext));
        var shariahReviewService = new ShariahReviewService(new ShariahReviewRepository(dbContext));
        var murabahaService = new MurabahaCaseService(new MurabahaCaseRepository(dbContext));
        var documentStorageRepository = new DocumentStorageRepository(dbContext);
        var murabahaContractService = new IslamicFinanceMurabahaContractService(new IslamicFinanceMurabahaContractRepository(dbContext, documentStorageRepository));
        var disbursementService = new IslamicFinanceMurabahaDisbursementService(new IslamicFinanceMurabahaDisbursementRepository(dbContext));

        var partner = CreateActivePartner(partnerService);
        var product = CreateActiveProduct(productService);
        var facility = CreateActiveFacility(facilityService, partner.Id, product.Id);
        var template = CreateActiveTemplate(templateService, product.Id);

        var request = requestService.CreateRequest(new CreateIslamicFinanceFinancingRequestRequest
        {
            RequestNumber = $"REQ-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            CustomerPartyId = 1,
            ProductProfileId = product.Id,
            FacilityId = facility.Id,
            FundingSourceMode = "PARTNER",
            SourceDocumentType = "SALES_ORDER",
            SourceDocumentId = 9100,
            TransactionCurrencyCode = "EGP",
            RequestedAmount = 120000m
        });
        requestService.SubmitRequest(request.Id, 3);
        requestService.ApproveRequest(request.Id, 4);
        request = requestService.AssignPartnerLender(request.Id, new AssignIslamicFinancePartnerLenderRequest
        {
            PartnerLenderId = partner.Id
        }, 3);

        var decision = requestService.CreateDecision(request.Id, new CreateIslamicFinanceDecisionRequest
        {
            DecisionCode = "APPROVED",
            DecisionNotes = "Approved for Islamic Finance event baseline.",
            DecidingPartyId = 1,
            PartnerLenderId = partner.Id
        });
        requestService.SubmitDecision(decision.Id, 3);
        decision = requestService.ApproveDecision(decision.Id, 4);

        var review = shariahReviewService.CreateReviewCase(new CreateIslamicFinanceShariahReviewRequest
        {
            ReviewCaseNumber = $"SHR-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            ProductProfileId = product.Id,
            FinancingRequestId = request.Id,
            ReviewReasonCode = "SHARIAH_REVIEW"
        });
        shariahReviewService.SubmitReviewCase(review.Id, 3);
        shariahReviewService.RecommendOutcome(review.Id, new RecommendIslamicFinanceShariahOutcomeRequest
        {
            ReviewOutcomeCode = "APPROVED",
            ReviewNotes = "Approved for operational Islamic Finance flow."
        }, 3);
        review = shariahReviewService.ApproveOutcome(review.Id, 4);

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

        var murabahaCase = murabahaService.CreateCase(new CreateIslamicFinanceMurabahaCaseRequest
        {
            CaseNumber = $"MUR-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            FinancingRequestId = request.Id,
            CustomerPartyId = request.CustomerPartyId,
            PartnerLenderId = partner.Id,
            SupplierPartyId = 2,
            ProductProfileId = product.Id,
            ContractTemplateId = template.Id,
            TransactionCurrencyCode = request.TransactionCurrencyCode,
            PurchaseCostAmount = 100000m,
            ProfitAmount = 20000m
        });
        murabahaService.SubmitCase(murabahaCase.Id, 3);
        murabahaService.ApproveCase(murabahaCase.Id, 4);
        murabahaCase = murabahaService.ActivateCase(murabahaCase.Id, 4);

        murabahaContractService.GenerateContract(murabahaCase.Id, 3, new GenerateIslamicFinanceMurabahaContractRequest());
        murabahaService.GenerateSchedule(murabahaCase.Id, 3, new GenerateIslamicFinanceMurabahaScheduleRequest
        {
            InstallmentCount = 4,
            FirstDueDate = new DateOnly(2026, 5, 1),
            InstallmentIntervalMonths = 1
        });

        var disbursement = disbursementService.CreateDisbursement(new CreateIslamicFinanceMurabahaDisbursementRequest
        {
            MurabahaCaseId = murabahaCase.Id,
            DisbursementNumber = $"DIS-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            SupplierPartyId = 2,
            TargetType = "SUPPLIER_PAYMENT",
            InstructedAmount = 100000m,
            PlannedExecutionDate = new DateOnly(2026, 4, 20)
        });
        disbursementService.SubmitDisbursement(disbursement.Id, 3);
        disbursementService.ApproveDisbursement(disbursement.Id, 4);
        disbursementService.ExecuteDisbursement(disbursement.Id, new ExecuteIslamicFinanceMurabahaDisbursementRequest
        {
            ExecutionReferenceNumber = $"EXEC-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            ExecutedAtUtc = new DateTime(2026, 4, 5, 10, 0, 0, DateTimeKind.Utc),
            ExecutedAmount = 100000m,
            ExecutionNotes = "Executed for Islamic Finance integration baseline."
        }, 4);
        disbursement = disbursementService.CloseDisbursement(disbursement.Id, 4);

        return new IslamicFinanceIntegrationSeedResult(
            partner.Id,
            product.Id,
            facility.Id,
            request.Id,
            request.RequestNumber,
            decision.Id,
            review.Id,
            review.ReviewCaseNumber,
            murabahaCase.Id,
            murabahaCase.CaseNumber,
            disbursement.Id,
            disbursement.DisbursementNumber);
    }

    private static IslamicFinancePartnerLenderResponse CreateActivePartner(IslamicFinancePartnerService service)
    {
        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-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            ProductName = "Murabaha Integration 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-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            CurrencyCode = "EGP",
            ApprovedLimitAmount = 250000m,
            UtilizedAmount = 0m
        });

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

    private static IslamicFinanceContractTemplateResponse CreateActiveTemplate(
        IslamicFinanceContractTemplateService service,
        long productProfileId)
    {
        var created = service.CreateContractTemplate(new CreateIslamicFinanceContractTemplateRequest
        {
            ProductProfileId = productProfileId,
            TemplateCode = $"TPL-INT-{Guid.NewGuid():N}"[..15].ToUpperInvariant(),
            TemplateName = "Murabaha Integration Template",
            LanguageCode = "EN"
        });

        service.SubmitContractTemplate(created.Id, 3);
        service.ApproveContractTemplate(created.Id, 4);
        return service.ActivateContractTemplate(created.Id, 4);
    }
}

internal sealed record IslamicFinanceIntegrationSeedResult(
    long PartnerLenderId,
    long ProductProfileId,
    long FacilityId,
    long FinancingRequestId,
    string RequestNumber,
    long FinancingDecisionId,
    long ShariahReviewCaseId,
    string ReviewCaseNumber,
    long MurabahaCaseId,
    string MurabahaCaseNumber,
    long DisbursementId,
    string DisbursementNumber);
