using CashLineERP.Application.Internal;
using CashLineERP.Application.MasterData;
using CashLineERP.Contracts.MasterData;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

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

        var masterDataService = new ReferenceDataGovernanceService(new ReferenceDataGovernanceRepository(dbContext));
        var workbenchService = new InternalWorkbenchService(new InternalWorkbenchRepository(dbContext));

        var createdEntry = masterDataService.CreateReferenceDataEntry(new CreateReferenceDataEntryRequest(
            ReferenceTypeCode: "WAREHOUSE",
            ReferenceCode: "DIST_WH",
            ReferenceName: "Distribution Warehouse",
            LocalizedName: "مخزن التوزيع",
            DescriptionText: "Secondary dispatch warehouse.",
            AttributesJson: "{\"branchId\":1,\"dispatchEnabled\":true,\"locationModel\":\"AISLE_BIN\"}",
            EffectiveFrom: new DateOnly(2026, 5, 1),
            EffectiveTo: null));

        Assert.Equal("DRAFT", createdEntry.StatusCode);
        Assert.False(createdEntry.IsActive);

        var submittedEntry = masterDataService.SubmitReferenceDataEntry(createdEntry.ReferenceDataEntryId, 2);
        Assert.Equal("SUBMITTED", submittedEntry.StatusCode);

        var approvalQueue = workbenchService.GetApprovalQueue("MASTER_DATA");
        var approvalItem = Assert.Single(approvalQueue);
        Assert.Equal("REFERENCE_DATA_ENTRY", approvalItem.DocumentType);
        Assert.Equal("DIST_WH", approvalItem.DocumentNumber);
        Assert.Equal(1L, approvalItem.BranchId);

        var approvedEntry = masterDataService.ApproveReferenceDataEntry(createdEntry.ReferenceDataEntryId, 4);
        Assert.Equal("APPROVED", approvedEntry.StatusCode);

        var activeEntry = masterDataService.ActivateReferenceDataEntry(createdEntry.ReferenceDataEntryId, 4);
        Assert.True(activeEntry.IsActive);

        var overview = masterDataService.GetOverview();
        Assert.True(overview.ActiveEntries >= 1);
        Assert.True(overview.WarehouseEntries >= 2);
    }

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

        var masterDataService = new ReferenceDataGovernanceService(new ReferenceDataGovernanceRepository(dbContext));

        var createdEntry = masterDataService.CreateReferenceDataEntry(new CreateReferenceDataEntryRequest(
            ReferenceTypeCode: "TAX_CODE",
            ReferenceCode: "VAT20",
            ReferenceName: "VAT 20 Percent",
            LocalizedName: null,
            DescriptionText: "Proposed tax code",
            AttributesJson: "{\"ratePercent\":20}",
            EffectiveFrom: new DateOnly(2026, 6, 1),
            EffectiveTo: null));

        masterDataService.SubmitReferenceDataEntry(createdEntry.ReferenceDataEntryId, 2);

        var selfApprovalException = Assert.Throws<InvalidOperationException>(() =>
            masterDataService.ApproveReferenceDataEntry(createdEntry.ReferenceDataEntryId, 2));
        Assert.Contains("self-approval", selfApprovalException.Message, StringComparison.OrdinalIgnoreCase);

        masterDataService.ApproveReferenceDataEntry(createdEntry.ReferenceDataEntryId, 4);
        masterDataService.ActivateReferenceDataEntry(createdEntry.ReferenceDataEntryId, 4);

        var duplicateEntry = masterDataService.CreateReferenceDataEntry(new CreateReferenceDataEntryRequest(
            ReferenceTypeCode: "TAX_CODE",
            ReferenceCode: "VAT20",
            ReferenceName: "VAT 20 Percent Replacement",
            LocalizedName: null,
            DescriptionText: "Duplicate active tax code",
            AttributesJson: "{\"ratePercent\":20}",
            EffectiveFrom: new DateOnly(2026, 7, 1),
            EffectiveTo: null));

        masterDataService.SubmitReferenceDataEntry(duplicateEntry.ReferenceDataEntryId, 2);
        masterDataService.ApproveReferenceDataEntry(duplicateEntry.ReferenceDataEntryId, 4);

        var duplicateActivationException = Assert.Throws<InvalidOperationException>(() =>
            masterDataService.ActivateReferenceDataEntry(duplicateEntry.ReferenceDataEntryId, 4));
        Assert.Contains("already exists", duplicateActivationException.Message, StringComparison.OrdinalIgnoreCase);
    }
}
