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

namespace CashLineERP.Api.Tests;

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

        var stockCountService = new StockCountService(new StockCountRepository(dbContext));
        var inventoryMovementService = new InventoryMovementService(new InventoryMovementReadRepository(dbContext));
        var generalLedgerService = new GeneralLedgerService(new GeneralLedgerReadRepository(dbContext));
        var inventoryAdjustmentService = new InventoryAdjustmentService(new InventoryAdjustmentRepository(dbContext));

        var created = stockCountService.CreateStockCount(new CreateStockCountRequest(
            BranchId: 1,
            WarehouseId: 1,
            CountDate: new DateOnly(2026, 5, 12),
            CountTypeCode: "CYCLE_COUNT",
            Notes: "Warehouse cycle count baseline.",
            Lines:
            [
                new CreateStockCountLineRequest(1001, null, 10m, 12m, "EA", 24m, "AVAILABLE", "COUNT-BATCH-1001-A", null, "Overage found"),
                new CreateStockCountLineRequest(1002, null, 8m, 7m, "BOX", 40m, "AVAILABLE", "COUNT-BATCH-1002-A", null, "Shortage found")
            ]));

        Assert.Equal("DRAFT", created.StatusCode);
        Assert.Equal(88m, created.TotalVarianceAmount);

        var submitted = stockCountService.SubmitStockCount(created.StockCountId, 31);
        Assert.Equal("SUBMITTED", submitted.StatusCode);

        var selfApprovalError = Assert.Throws<InvalidOperationException>(() =>
            stockCountService.ApproveStockCount(created.StockCountId, 31));
        Assert.Contains("self-approval", selfApprovalError.Message, StringComparison.OrdinalIgnoreCase);

        var approved = stockCountService.ApproveStockCount(created.StockCountId, 32);
        Assert.Equal("APPROVED", approved.StatusCode);

        var posted = stockCountService.PostStockCount(created.StockCountId, 33);
        Assert.Equal("POSTED", posted.StatusCode);
        Assert.NotNull(posted.InventoryAdjustmentId);
        Assert.NotNull(posted.GeneralLedgerBatchId);

        var linkedAdjustment = inventoryAdjustmentService.GetInventoryAdjustment(posted.InventoryAdjustmentId!.Value);
        Assert.NotNull(linkedAdjustment);
        Assert.Equal("POSTED", linkedAdjustment!.StatusCode);

        var movements = inventoryMovementService.GetInventoryMovements()
            .Where(movement => movement.MovementType is "ADJUSTMENT_GAIN" or "ADJUSTMENT_LOSS")
            .ToArray();

        Assert.Contains(movements, movement => movement.MovementType == "ADJUSTMENT_GAIN" && movement.QuantityMoved == 2m && movement.UnitCost == 24m);
        Assert.Contains(movements, movement => movement.MovementType == "ADJUSTMENT_LOSS" && movement.QuantityMoved == 1m && movement.UnitCost == 40m);

        var ledgerBatch = generalLedgerService.GetGeneralLedgerBatches()
            .Single(batch => batch.BatchType == "INV_STOCK_COUNT" && batch.SourceDocumentId == created.StockCountId);

        Assert.Equal(posted.GeneralLedgerBatchId, ledgerBatch.GeneralLedgerBatchId);
        Assert.NotEmpty(ledgerBatch.Journals);
        Assert.All(ledgerBatch.Journals, journal => Assert.Equal("INV_STOCK_COUNT", journal.JournalType));
    }
}
