CreateWarehouseUseCase.java

package com.fulfilment.application.monolith.warehouses.domain.usecases;

import com.fulfilment.application.monolith.warehouses.domain.models.Location;
import com.fulfilment.application.monolith.warehouses.domain.models.Warehouse;
import com.fulfilment.application.monolith.warehouses.domain.ports.CreateWarehouseOperation;
import com.fulfilment.application.monolith.warehouses.domain.ports.LocationResolver;
import com.fulfilment.application.monolith.warehouses.domain.ports.WarehouseStore;
import jakarta.enterprise.context.ApplicationScoped;
import com.fulfilment.application.monolith.exception.HttpStatus;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
import java.time.LocalDateTime;
import java.util.List;
import org.jboss.logging.Logger;

@ApplicationScoped
public class CreateWarehouseUseCase implements CreateWarehouseOperation {

  private static final Logger LOGGER = Logger.getLogger(CreateWarehouseUseCase.class.getName());

  private final WarehouseStore warehouseStore;
  private final LocationResolver locationResolver;

  public CreateWarehouseUseCase(WarehouseStore warehouseStore, LocationResolver locationResolver) {
    this.warehouseStore = warehouseStore;
    this.locationResolver = locationResolver;
  }

  @Override
  public void create(Warehouse warehouse) {
    LOGGER.debugf("Attempting to create warehouse with businessUnitCode: %s at location: %s",
        warehouse.businessUnitCode, warehouse.location);

    // 1. Validate location exists
    Location location = locationResolver.resolveByIdentifier(warehouse.location);
    if (location == null) {
      LOGGER.warnf("Location '%s' not found", warehouse.location);
      throw new BadRequestException(
          "Location '" + warehouse.location + "' does not exist.");
    }

    // 2. Validate business unit code is unique among active warehouses
    Warehouse existing = warehouseStore.findByBusinessUnitCode(warehouse.businessUnitCode);
    if (existing != null) {
      LOGGER.warnf("Warehouse with businessUnitCode '%s' already exists", warehouse.businessUnitCode);
      throw new WebApplicationException(
          "Warehouse with business unit code '" + warehouse.businessUnitCode + "' already exists.", Response.Status.CONFLICT);
    }

    // 3. Check location has not reached its max number of warehouses
    List<Warehouse> warehousesAtLocation = warehouseStore.getAll().stream()
        .filter(w -> warehouse.location.equals(w.location))
        .toList();

    if (warehousesAtLocation.size() >= location.maxNumberOfWarehouses) {
      LOGGER.warnf("Location '%s' has reached max warehouse count of %d",
          warehouse.location, location.maxNumberOfWarehouses);
      throw new WebApplicationException(
          "Location '" + warehouse.location + "' has reached the maximum number of warehouses ("
              + location.maxNumberOfWarehouses + ").", HttpStatus.UNPROCESSABLE_ENTITY);
    }

    // 4. Check location total capacity is not exceeded
    int usedCapacity = warehousesAtLocation.stream()
        .mapToInt(w -> w.capacity)
        .sum();

    if (usedCapacity + warehouse.capacity > location.maxCapacity) {
      LOGGER.warnf("Location '%s' max capacity %d would be exceeded (used: %d, new: %d)",
          warehouse.location, location.maxCapacity, usedCapacity, warehouse.capacity);
      throw new WebApplicationException(
          "Adding this warehouse would exceed the maximum capacity of location '"
              + warehouse.location + "' (max: " + location.maxCapacity
              + ", used: " + usedCapacity + ", requested: " + warehouse.capacity + ").", HttpStatus.UNPROCESSABLE_ENTITY);
    }

    // 5. Validate warehouse capacity can accommodate its stock
    if (warehouse.capacity < warehouse.stock) {
      LOGGER.warnf("Warehouse capacity %d is less than stock %d", warehouse.capacity, warehouse.stock);
      throw new WebApplicationException(
          "Warehouse capacity (" + warehouse.capacity + ") cannot be less than its stock ("
              + warehouse.stock + ").", HttpStatus.UNPROCESSABLE_ENTITY);
    }

    // All validations passed — set creation timestamp and persist
    warehouse.createdAt = LocalDateTime.now();
    warehouseStore.create(warehouse);

    LOGGER.infof("Warehouse '%s' created successfully at location '%s'",
        warehouse.businessUnitCode, warehouse.location);
  }
}