using CashLineERP.Application.Health;
using CashLineERP.Application.Identity;
using CashLineERP.Application.Parties;
using CashLineERP.Application.Workflow;
using CashLineERP.Contracts.Auth;
using CashLineERP.Contracts.Parties;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

public sealed class PlatformAndOnboardingServiceQaTests
{
    [Fact]
    public void Platform_Foundation_Services_Return_Expected_Seeded_Data_And_Login_Behavior()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var healthService = new ApplicationHealthService();
        var identityService = new IdentityService(new IdentityReadRepository(dbContext), new FakeAccessTokenService());
        var workflowService = new WorkflowService(new WorkflowReadRepository(dbContext));

        var health = healthService.GetCurrentStatus("Development", "1.0.0");
        Assert.Equal("OK", health.Status);
        Assert.Equal("Development", health.Environment);
        Assert.Equal("1.0.0", health.Version);

        var internalLogin = identityService.Login(new LoginRequest("OPS_MKR01", "OpsMkr01!", "internal"));
        Assert.True(internalLogin.MfaRequired);
        Assert.Equal(3600, internalLogin.ExpiresInSeconds);

        var externalLogin = identityService.Login(new LoginRequest("SUPPLIER_ADMIN01", "Supplier01!", "external"));
        Assert.False(externalLogin.MfaRequired);

        Assert.Throws<InvalidOperationException>(() => identityService.Login(new LoginRequest("UNKNOWN_USER", "ignored", "internal")));

        var roles = identityService.GetRoles();
        Assert.Contains(roles, role => role.RoleCode == "FINANCE_CHECKER" && role.IsChecker);
        Assert.Contains(roles, role => role.RoleCode == "SUPPLIER_ADMIN" && role.PortalCode == "EXTERNAL");

        var queue = workflowService.GetPendingQueue();
        var queueItem = Assert.Single(queue);
        Assert.Equal("PROCUREMENT", queueItem.ModuleCode);
        Assert.Equal("PURCHASE_REQUISITION", queueItem.DocumentType);
        Assert.Equal("PR-000001", queueItem.DocumentNumber);
        Assert.Equal("SUBMITTED", queueItem.CurrentStatus);
        Assert.Equal("OPS_MKR01", queueItem.SubmittedBy);
    }

    [Fact]
    public void Party_Onboarding_Can_Create_And_Filter_Customer_And_Supplier_Parties()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var service = new PartyOnboardingService(new BusinessPartyRepository(dbContext));

        var createdCustomer = service.CreateParty(new CreateBusinessPartyRequest(
            PartyCode: "CUS-TEST-100",
            PartyName: "Alex Test Customer",
            PartyType: "CUSTOMER",
            CountryCode: "EG",
            FirmNationalId: null,
            TaxRegistrationNumber: "77889911",
            TaxBranchCode: "005",
            Email: "customer.test@example.local",
            MobileNumber: "+201111111111",
            AddressLine1: "Alexandria",
            CreditLimitAmount: 2500m,
            CreditTermsDays: 21,
            IsCreditHoldEnabled: false,
            CreditHoldReason: null));

        var createdSupplier = service.CreateParty(new CreateBusinessPartyRequest(
            PartyCode: "SUP-TEST-200",
            PartyName: "Cairo Test Supplier",
            PartyType: "SUPPLIER",
            CountryCode: "EG",
            FirmNationalId: null,
            TaxRegistrationNumber: "33445566",
            TaxBranchCode: "004",
            Email: "supplier.test@example.local",
            MobileNumber: "+201222222222",
            AddressLine1: "Cairo",
            CreditLimitAmount: null,
            CreditTermsDays: null,
            IsCreditHoldEnabled: false,
            CreditHoldReason: null));

        Assert.True(createdCustomer.IsActive);
        Assert.True(createdSupplier.IsActive);
        Assert.Equal(2500m, createdCustomer.CreditLimitAmount);
        Assert.Equal(21, createdCustomer.CreditTermsDays);

        var customers = service.GetParties("CUSTOMER");
        var suppliers = service.GetParties("SUPPLIER");
        var allParties = service.GetParties();

        Assert.Contains(customers, party => party.PartyCode == "CUS-TEST-100" && party.PartyType == "CUSTOMER");
        Assert.Contains(suppliers, party => party.PartyCode == "SUP-TEST-200" && party.PartyType == "SUPPLIER");
        Assert.Contains(allParties, party => party.PartyCode == "CUS-TEST-100");
        Assert.Contains(allParties, party => party.PartyCode == "SUP-TEST-200");
    }
}
