package de.effigenix.infrastructure.config;

import de.effigenix.application.production.ActivateRecipe;
import de.effigenix.application.production.ArchiveRecipe;
import de.effigenix.application.production.AddProductionStep;
import de.effigenix.application.production.AddRecipeIngredient;
import de.effigenix.application.production.CancelProductionOrder;
import de.effigenix.application.production.CompleteProductionOrder;
import de.effigenix.application.production.CreateProductionOrder;
import de.effigenix.application.production.GetProductionOrder;
import de.effigenix.application.production.ListProductionOrders;
import de.effigenix.application.production.ReleaseProductionOrder;
import de.effigenix.application.production.RescheduleProductionOrder;
import de.effigenix.application.production.StartProductionOrder;
import de.effigenix.application.production.CancelBatch;
import de.effigenix.application.production.CompleteBatch;
import de.effigenix.application.production.CreateRecipe;
import de.effigenix.application.production.TraceBatchBackward;
import de.effigenix.application.production.TraceBatchForward;
import de.effigenix.application.production.FindBatchByNumber;
import de.effigenix.application.production.GetBatch;
import de.effigenix.application.production.ListBatches;
import de.effigenix.application.production.PlanBatch;
import de.effigenix.application.production.RecordConsumption;
import de.effigenix.application.production.StartBatch;
import de.effigenix.application.production.RecipeCycleChecker;
import de.effigenix.application.production.GetRecipe;
import de.effigenix.application.production.ListRecipes;
import de.effigenix.application.production.RemoveProductionStep;
import de.effigenix.application.production.RemoveRecipeIngredient;
import de.effigenix.domain.production.BatchNumberGenerator;
import de.effigenix.domain.production.BatchRepository;
import de.effigenix.domain.production.BatchTraceabilityService;
import de.effigenix.domain.production.ProductionOrderRepository;
import de.effigenix.domain.production.RecipeRepository;
import de.effigenix.shared.event.DomainEventPublisher;
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 ProductionUseCaseConfiguration {

    @Bean
    public CreateRecipe createRecipe(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                     UnitOfWork unitOfWork) {
        return new CreateRecipe(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public RecipeCycleChecker recipeCycleChecker(RecipeRepository recipeRepository) {
        return new RecipeCycleChecker(recipeRepository);
    }

    @Bean
    public AddRecipeIngredient addRecipeIngredient(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                                   RecipeCycleChecker recipeCycleChecker, UnitOfWork unitOfWork) {
        return new AddRecipeIngredient(recipeRepository, authorizationPort, recipeCycleChecker, unitOfWork);
    }

    @Bean
    public RemoveRecipeIngredient removeRecipeIngredient(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                                         UnitOfWork unitOfWork) {
        return new RemoveRecipeIngredient(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public AddProductionStep addProductionStep(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                               UnitOfWork unitOfWork) {
        return new AddProductionStep(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public RemoveProductionStep removeProductionStep(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                                     UnitOfWork unitOfWork) {
        return new RemoveProductionStep(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public GetRecipe getRecipe(RecipeRepository recipeRepository, AuthorizationPort authorizationPort) {
        return new GetRecipe(recipeRepository, authorizationPort);
    }

    @Bean
    public ListRecipes listRecipes(RecipeRepository recipeRepository, AuthorizationPort authorizationPort) {
        return new ListRecipes(recipeRepository, authorizationPort);
    }

    @Bean
    public ActivateRecipe activateRecipe(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                         UnitOfWork unitOfWork) {
        return new ActivateRecipe(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public ArchiveRecipe archiveRecipe(RecipeRepository recipeRepository, AuthorizationPort authorizationPort,
                                       UnitOfWork unitOfWork) {
        return new ArchiveRecipe(recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public PlanBatch planBatch(BatchRepository batchRepository, RecipeRepository recipeRepository,
                               BatchNumberGenerator batchNumberGenerator, AuthorizationPort authorizationPort,
                               UnitOfWork unitOfWork) {
        return new PlanBatch(batchRepository, recipeRepository, batchNumberGenerator, authorizationPort, unitOfWork);
    }

    @Bean
    public GetBatch getBatch(BatchRepository batchRepository, AuthorizationPort authorizationPort) {
        return new GetBatch(batchRepository, authorizationPort);
    }

    @Bean
    public ListBatches listBatches(BatchRepository batchRepository, RecipeRepository recipeRepository,
                                   AuthorizationPort authorizationPort) {
        return new ListBatches(batchRepository, recipeRepository, authorizationPort);
    }

    @Bean
    public FindBatchByNumber findBatchByNumber(BatchRepository batchRepository, AuthorizationPort authorizationPort) {
        return new FindBatchByNumber(batchRepository, authorizationPort);
    }

    @Bean
    public StartBatch startBatch(BatchRepository batchRepository, AuthorizationPort authorizationPort,
                                 UnitOfWork unitOfWork) {
        return new StartBatch(batchRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public RecordConsumption recordConsumption(BatchRepository batchRepository, AuthorizationPort authorizationPort,
                                               DomainEventPublisher domainEventPublisher, UnitOfWork unitOfWork) {
        return new RecordConsumption(batchRepository, authorizationPort, domainEventPublisher, unitOfWork);
    }

    @Bean
    public CompleteBatch completeBatch(BatchRepository batchRepository, RecipeRepository recipeRepository,
                                       AuthorizationPort authorizationPort, DomainEventPublisher domainEventPublisher,
                                       UnitOfWork unitOfWork) {
        return new CompleteBatch(batchRepository, recipeRepository, authorizationPort, domainEventPublisher, unitOfWork);
    }

    @Bean
    public CancelBatch cancelBatch(BatchRepository batchRepository, AuthorizationPort authorizationPort,
                                   UnitOfWork unitOfWork) {
        return new CancelBatch(batchRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public BatchTraceabilityService batchTraceabilityService(BatchRepository batchRepository) {
        return new BatchTraceabilityService(batchRepository);
    }

    @Bean
    public TraceBatchForward traceBatchForward(BatchTraceabilityService batchTraceabilityService,
                                               AuthorizationPort authorizationPort) {
        return new TraceBatchForward(batchTraceabilityService, authorizationPort);
    }

    @Bean
    public TraceBatchBackward traceBatchBackward(BatchTraceabilityService batchTraceabilityService,
                                                 AuthorizationPort authorizationPort) {
        return new TraceBatchBackward(batchTraceabilityService, authorizationPort);
    }

    @Bean
    public CreateProductionOrder createProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                        RecipeRepository recipeRepository,
                                                        AuthorizationPort authorizationPort,
                                                        UnitOfWork unitOfWork) {
        return new CreateProductionOrder(productionOrderRepository, recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public ReleaseProductionOrder releaseProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                          RecipeRepository recipeRepository,
                                                          AuthorizationPort authorizationPort,
                                                          UnitOfWork unitOfWork) {
        return new ReleaseProductionOrder(productionOrderRepository, recipeRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public StartProductionOrder startProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                     BatchRepository batchRepository,
                                                     RecipeRepository recipeRepository,
                                                     BatchNumberGenerator batchNumberGenerator,
                                                     AuthorizationPort authorizationPort,
                                                     UnitOfWork unitOfWork) {
        return new StartProductionOrder(productionOrderRepository, batchRepository, recipeRepository,
                batchNumberGenerator, authorizationPort, unitOfWork);
    }

    @Bean
    public CompleteProductionOrder completeProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                            BatchRepository batchRepository,
                                                            AuthorizationPort authorizationPort,
                                                            UnitOfWork unitOfWork) {
        return new CompleteProductionOrder(productionOrderRepository, batchRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public CancelProductionOrder cancelProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                        AuthorizationPort authorizationPort,
                                                        UnitOfWork unitOfWork) {
        return new CancelProductionOrder(productionOrderRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public RescheduleProductionOrder rescheduleProductionOrder(ProductionOrderRepository productionOrderRepository,
                                                                AuthorizationPort authorizationPort,
                                                                UnitOfWork unitOfWork) {
        return new RescheduleProductionOrder(productionOrderRepository, authorizationPort, unitOfWork);
    }

    @Bean
    public GetProductionOrder getProductionOrder(ProductionOrderRepository productionOrderRepository) {
        return new GetProductionOrder(productionOrderRepository);
    }

    @Bean
    public ListProductionOrders listProductionOrders(ProductionOrderRepository productionOrderRepository,
                                                      AuthorizationPort authorizationPort) {
        return new ListProductionOrders(productionOrderRepository, authorizationPort);
    }
}
