using CashLineERP.Application.Inventory;
using CashLineERP.Contracts.Inventory;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

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

        var controlService = new InventoryStatusControlService(new InventoryStatusControlRepository(dbContext));
        var movementService = new InventoryMovementService(new InventoryMovementReadRepository(dbContext));

        var created = controlService.CreateInventoryStatusControl(new CreateInventoryStatusControlRequest(
            BranchId: 1,
            WarehouseId: 1,
            ControlDate: new DateOnly(2026, 5, 23),
            ReasonCode: "QUALITY_REVIEW",
            Notes: "Status control baseline",
            Lines:
            [
                new CreateInventoryStatusControlLineRequest(1001, null, 3m, "EA", 24m, "AVAILABLE", "QUARANTINE", "BATCH-1001-A", null, null, "Quality review hold"),
                new CreateInventoryStatusControlLineRequest(1001, null, 1m, "EA", 24m, "AVAILABLE", "EXPIRED", "BATCH-1001-A", null, new DateOnly(2026, 5, 20), "Expired stock reclass")
            ]));

        Assert.Equal("DRAFT", created.StatusCode);
        Assert.Equal(4m, created.TotalQuantityAffected);

        var submitted = controlService.SubmitInventoryStatusControl(created.InventoryStatusControlId, 7);
        Assert.Equal("SUBMITTED", submitted.StatusCode);

        var approved = controlService.ApproveInventoryStatusControl(created.InventoryStatusControlId, 8);
        Assert.Equal("APPROVED", approved.StatusCode);

        var posted = controlService.PostInventoryStatusControl(created.InventoryStatusControlId, 9);
        Assert.Equal("POSTED", posted.StatusCode);

        var movements = movementService.GetInventoryMovements()
            .Where(movement => movement.MovementType is "STATUS_RECLASS_OUT" or "STATUS_RECLASS_IN")
            .ToArray();

        Assert.Contains(movements, movement => movement.MovementType == "STATUS_RECLASS_OUT" && movement.StockStatus == "AVAILABLE" && movement.QuantityMoved == 3m);
        Assert.Contains(movements, movement => movement.MovementType == "STATUS_RECLASS_IN" && movement.StockStatus == "QUARANTINE" && movement.QuantityMoved == 3m);
        Assert.Contains(movements, movement => movement.MovementType == "STATUS_RECLASS_IN" && movement.StockStatus == "EXPIRED" && movement.QuantityMoved == 1m);

        var traceability = movementService.GetLotTraceability("BATCH-1001-A");
        Assert.NotNull(traceability);
        Assert.Contains(traceability!.Positions, position => position.StockStatus == "QUARANTINE" && position.NetQuantity == 3m);
        Assert.Contains(traceability.Positions, position => position.StockStatus == "EXPIRED" && position.NetQuantity == 1m);
        Assert.Contains(traceability.Positions, position => position.StockStatus == "AVAILABLE" && position.NetQuantity == 46m);
    }

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

        var controlService = new InventoryStatusControlService(new InventoryStatusControlRepository(dbContext));

        var expiryError = Assert.Throws<InvalidOperationException>(() =>
            controlService.CreateInventoryStatusControl(new CreateInventoryStatusControlRequest(
                BranchId: 1,
                WarehouseId: 1,
                ControlDate: new DateOnly(2026, 5, 21),
                ReasonCode: "EXPIRY_REVIEW",
                Notes: "Invalid expiry attempt",
                Lines:
                [
                    new CreateInventoryStatusControlLineRequest(1001, null, 1m, "EA", 24m, "AVAILABLE", "EXPIRED", "BATCH-1001-A", null, new DateOnly(2026, 5, 25), "Future expiry")
                ])));
        Assert.Contains("expired", expiryError.Message, StringComparison.OrdinalIgnoreCase);

        var created = controlService.CreateInventoryStatusControl(new CreateInventoryStatusControlRequest(
            BranchId: 1,
            WarehouseId: 1,
            ControlDate: new DateOnly(2026, 5, 21),
            ReasonCode: "QUALITY_REVIEW",
            Notes: "Valid quarantine control",
            Lines:
            [
                new CreateInventoryStatusControlLineRequest(1001, null, 1m, "EA", 24m, "AVAILABLE", "QUARANTINE", "BATCH-1001-A", null, null, "Quality hold")
            ]));

        controlService.SubmitInventoryStatusControl(created.InventoryStatusControlId, 12);

        var selfApprovalError = Assert.Throws<InvalidOperationException>(() =>
            controlService.ApproveInventoryStatusControl(created.InventoryStatusControlId, 12));
        Assert.Contains("self-approval", selfApprovalError.Message, StringComparison.OrdinalIgnoreCase);

        var prematurePostError = Assert.Throws<InvalidOperationException>(() =>
            controlService.PostInventoryStatusControl(created.InventoryStatusControlId, 14));
        Assert.Contains("approved", prematurePostError.Message, StringComparison.OrdinalIgnoreCase);
    }
}
