package de.effigenix.infrastructure.config;

import de.effigenix.application.inventory.CancelInventoryCount;
import de.effigenix.application.inventory.CompleteInventoryCount;
import de.effigenix.application.inventory.CreateInventoryCount;
import de.effigenix.application.inventory.GetInventoryCount;
import de.effigenix.application.inventory.ListInventoryCounts;
import de.effigenix.application.inventory.RecordCountItem;
import de.effigenix.application.inventory.StartInventoryCount;
import de.effigenix.application.inventory.GetStockMovement;
import de.effigenix.application.inventory.ListStockMovements;
import de.effigenix.application.inventory.BookProductionConsumption;
import de.effigenix.application.inventory.BookProductionOutput;
import de.effigenix.application.inventory.ConfirmReservation;
import de.effigenix.application.inventory.RecordStockMovement;
import de.effigenix.application.inventory.ActivateStorageLocation;
import de.effigenix.application.inventory.AddStockBatch;
import de.effigenix.application.inventory.BlockStockBatch;
import de.effigenix.application.inventory.CheckStockExpiry;
import de.effigenix.application.inventory.CreateStock;
import de.effigenix.application.inventory.GetStock;
import de.effigenix.application.inventory.UpdateStock;
import de.effigenix.application.inventory.ListStocks;
import de.effigenix.application.inventory.ListStocksBelowMinimum;
import de.effigenix.application.inventory.RemoveStockBatch;
import de.effigenix.application.inventory.ReleaseReservation;
import de.effigenix.application.inventory.ReserveStock;
import de.effigenix.application.inventory.UnblockStockBatch;
import de.effigenix.application.inventory.CreateStorageLocation;
import de.effigenix.application.inventory.DeactivateStorageLocation;
import de.effigenix.application.inventory.GetStorageLocation;
import de.effigenix.application.inventory.ListStorageLocations;
import de.effigenix.application.inventory.UpdateStorageLocation;
import de.effigenix.application.usermanagement.AuditLogger;
import de.effigenix.domain.inventory.InventoryCountReconciliationService;
import de.effigenix.domain.inventory.InventoryCountRepository;
import de.effigenix.domain.inventory.StockMovementRepository;
import de.effigenix.domain.inventory.StockRepository;
import de.effigenix.domain.inventory.StorageLocationRepository;
import de.effigenix.shared.persistence.UnitOfWork;
import de.effigenix.shared.security.AuthorizationPort;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class InventoryUseCaseConfiguration {

    // ==================== StorageLocation Use Cases ====================

    @Bean
    public CreateStorageLocation createStorageLocation(StorageLocationRepository storageLocationRepository, UnitOfWork unitOfWork) {
        return new CreateStorageLocation(storageLocationRepository, unitOfWork);
    }

    @Bean
    public UpdateStorageLocation updateStorageLocation(StorageLocationRepository storageLocationRepository, UnitOfWork unitOfWork) {
        return new UpdateStorageLocation(storageLocationRepository, unitOfWork);
    }

    @Bean
    public DeactivateStorageLocation deactivateStorageLocation(StorageLocationRepository storageLocationRepository, StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new DeactivateStorageLocation(storageLocationRepository, stockRepository, unitOfWork);
    }

    @Bean
    public ActivateStorageLocation activateStorageLocation(StorageLocationRepository storageLocationRepository, UnitOfWork unitOfWork) {
        return new ActivateStorageLocation(storageLocationRepository, unitOfWork);
    }

    @Bean
    public GetStorageLocation getStorageLocation(StorageLocationRepository storageLocationRepository, AuthorizationPort authorizationPort) {
        return new GetStorageLocation(storageLocationRepository, authorizationPort);
    }

    @Bean
    public ListStorageLocations listStorageLocations(StorageLocationRepository storageLocationRepository) {
        return new ListStorageLocations(storageLocationRepository);
    }

    // ==================== Stock Use Cases ====================

    @Bean
    public CreateStock createStock(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new CreateStock(stockRepository, unitOfWork);
    }

    @Bean
    public UpdateStock updateStock(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new UpdateStock(stockRepository, unitOfWork);
    }

    @Bean
    public GetStock getStock(StockRepository stockRepository) {
        return new GetStock(stockRepository);
    }

    @Bean
    public ListStocks listStocks(StockRepository stockRepository) {
        return new ListStocks(stockRepository);
    }

    @Bean
    public AddStockBatch addStockBatch(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new AddStockBatch(stockRepository, unitOfWork);
    }

    @Bean
    public RemoveStockBatch removeStockBatch(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new RemoveStockBatch(stockRepository, unitOfWork);
    }

    @Bean
    public BlockStockBatch blockStockBatch(StockRepository stockRepository, AuditLogger auditLogger, UnitOfWork unitOfWork) {
        return new BlockStockBatch(stockRepository, auditLogger, unitOfWork);
    }

    @Bean
    public UnblockStockBatch unblockStockBatch(StockRepository stockRepository, AuditLogger auditLogger, UnitOfWork unitOfWork) {
        return new UnblockStockBatch(stockRepository, auditLogger, unitOfWork);
    }

    @Bean
    public ReserveStock reserveStock(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new ReserveStock(stockRepository, unitOfWork);
    }

    @Bean
    public ReleaseReservation releaseReservation(StockRepository stockRepository, UnitOfWork unitOfWork) {
        return new ReleaseReservation(stockRepository, unitOfWork);
    }

    @Bean
    public ConfirmReservation confirmReservation(StockRepository stockRepository,
                                                  StockMovementRepository stockMovementRepository,
                                                  UnitOfWork unitOfWork) {
        return new ConfirmReservation(stockRepository, stockMovementRepository, unitOfWork);
    }

    @Bean
    public CheckStockExpiry checkStockExpiry(StockRepository stockRepository) {
        return new CheckStockExpiry(stockRepository);
    }

    @Bean
    public ListStocksBelowMinimum listStocksBelowMinimum(StockRepository stockRepository, AuthorizationPort authorizationPort) {
        return new ListStocksBelowMinimum(stockRepository, authorizationPort);
    }

    @Bean
    public BookProductionOutput bookProductionOutput(StockRepository stockRepository,
                                                      StorageLocationRepository storageLocationRepository,
                                                      StockMovementRepository stockMovementRepository,
                                                      UnitOfWork unitOfWork) {
        return new BookProductionOutput(stockRepository, storageLocationRepository, stockMovementRepository, unitOfWork);
    }

    @Bean
    public BookProductionConsumption bookProductionConsumption(StockRepository stockRepository,
                                                                StockMovementRepository stockMovementRepository,
                                                                UnitOfWork unitOfWork) {
        return new BookProductionConsumption(stockRepository, stockMovementRepository, unitOfWork);
    }

    // ==================== StockMovement Use Cases ====================

    @Bean
    public RecordStockMovement recordStockMovement(StockMovementRepository stockMovementRepository, AuthorizationPort authorizationPort, UnitOfWork unitOfWork) {
        return new RecordStockMovement(stockMovementRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public GetStockMovement getStockMovement(StockMovementRepository stockMovementRepository, AuthorizationPort authorizationPort) {
        return new GetStockMovement(stockMovementRepository, authorizationPort);
    }

    @Bean
    public ListStockMovements listStockMovements(StockMovementRepository stockMovementRepository, AuthorizationPort authorizationPort) {
        return new ListStockMovements(stockMovementRepository, authorizationPort);
    }

    // ==================== InventoryCount Use Cases ====================

    @Bean
    public CreateInventoryCount createInventoryCount(InventoryCountRepository inventoryCountRepository, StockRepository stockRepository, UnitOfWork unitOfWork, AuthorizationPort authorizationPort) {
        return new CreateInventoryCount(inventoryCountRepository, stockRepository, unitOfWork, authorizationPort);
    }

    @Bean
    public GetInventoryCount getInventoryCount(InventoryCountRepository inventoryCountRepository, AuthorizationPort authorizationPort) {
        return new GetInventoryCount(inventoryCountRepository, authorizationPort);
    }

    @Bean
    public ListInventoryCounts listInventoryCounts(InventoryCountRepository inventoryCountRepository, AuthorizationPort authorizationPort) {
        return new ListInventoryCounts(inventoryCountRepository, authorizationPort);
    }

    @Bean
    public StartInventoryCount startInventoryCount(InventoryCountRepository inventoryCountRepository, UnitOfWork unitOfWork, AuthorizationPort authorizationPort) {
        return new StartInventoryCount(inventoryCountRepository, unitOfWork, authorizationPort);
    }

    @Bean
    public RecordCountItem recordCountItem(InventoryCountRepository inventoryCountRepository, UnitOfWork unitOfWork, AuthorizationPort authorizationPort) {
        return new RecordCountItem(inventoryCountRepository, unitOfWork, authorizationPort);
    }

    @Bean
    public CancelInventoryCount cancelInventoryCount(InventoryCountRepository inventoryCountRepository, UnitOfWork unitOfWork, AuthorizationPort authorizationPort) {
        return new CancelInventoryCount(inventoryCountRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public InventoryCountReconciliationService inventoryCountReconciliationService() {
        return new InventoryCountReconciliationService();
    }

    @Bean
    public CompleteInventoryCount completeInventoryCount(InventoryCountRepository inventoryCountRepository,
                                                          StockRepository stockRepository,
                                                          StockMovementRepository stockMovementRepository,
                                                          InventoryCountReconciliationService reconciliationService,
                                                          UnitOfWork unitOfWork,
                                                          AuthorizationPort authorizationPort) {
        return new CompleteInventoryCount(inventoryCountRepository, stockRepository, stockMovementRepository, reconciliationService, unitOfWork, authorizationPort);
    }
}
