package de.effigenix.application.production;

import de.effigenix.domain.production.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId;
import de.effigenix.shared.security.AuthorizationPort;

import java.time.LocalDate;
import java.util.List;

public class ListProductionOrders {

    private final ProductionOrderRepository productionOrderRepository;
    private final AuthorizationPort authorizationPort;

    public ListProductionOrders(
            ProductionOrderRepository productionOrderRepository,
            AuthorizationPort authorizationPort
    ) {
        this.productionOrderRepository = productionOrderRepository;
        this.authorizationPort = authorizationPort;
    }

    public Result<ProductionOrderError, List<ProductionOrder>> execute(ActorId performedBy) {
        if (!authorizationPort.can(performedBy, ProductionAction.PRODUCTION_ORDER_READ)) {
            return Result.failure(new ProductionOrderError.Unauthorized("Not authorized to list production orders"));
        }

        return wrapResult(productionOrderRepository.findAll());
    }

    public Result<ProductionOrderError, List<ProductionOrder>> executeByDateRange(LocalDate from, LocalDate to, ActorId performedBy) {
        if (!authorizationPort.can(performedBy, ProductionAction.PRODUCTION_ORDER_READ)) {
            return Result.failure(new ProductionOrderError.Unauthorized("Not authorized to list production orders"));
        }

        return wrapResult(productionOrderRepository.findByDateRange(from, to));
    }

    public Result<ProductionOrderError, List<ProductionOrder>> executeByStatus(ProductionOrderStatus status, ActorId performedBy) {
        if (!authorizationPort.can(performedBy, ProductionAction.PRODUCTION_ORDER_READ)) {
            return Result.failure(new ProductionOrderError.Unauthorized("Not authorized to list production orders"));
        }

        return wrapResult(productionOrderRepository.findByStatus(status));
    }

    public Result<ProductionOrderError, List<ProductionOrder>> executeByDateRangeAndStatus(
            LocalDate from, LocalDate to, ProductionOrderStatus status, ActorId performedBy) {
        if (!authorizationPort.can(performedBy, ProductionAction.PRODUCTION_ORDER_READ)) {
            return Result.failure(new ProductionOrderError.Unauthorized("Not authorized to list production orders"));
        }

        return wrapResult(productionOrderRepository.findByDateRangeAndStatus(from, to, status));
    }

    private Result<ProductionOrderError, List<ProductionOrder>> wrapResult(Result<RepositoryError, List<ProductionOrder>> repoResult) {
        return switch (repoResult) {
            case Result.Failure(var err) -> Result.failure(new ProductionOrderError.RepositoryFailure(err.message()));
            case Result.Success(var orders) -> Result.success(orders);
        };
    }
}
