import {
  InsufficientReservedStockError,
  InsufficientStockError,
  InvalidStockQuantityError,
} from '../domain/errors.js';
import type {
  InventoryRepository,
  InventoryService as InventoryServicePort,
} from '../domain/ports.js';
import type {
  Availability,
  SetAvailableStockCommand,
  StockCommand,
  StockItem,
} from '../domain/stock.js';

export class InventoryService implements InventoryServicePort {
  constructor(private readonly repository: InventoryRepository) {}

  async checkAvailability(variantId: string, storeId: string, quantity: number): Promise<Availability> {
    ensurePositiveQuantity(quantity);
    const item = await this.repository.findByVariantId(variantId, storeId);
    const availableQuantity = item?.available ?? 0;
    return { available: availableQuantity >= quantity, availableQuantity };
  }

  async reserve(input: StockCommand): Promise<StockItem> {
    ensurePositiveQuantity(input.quantity);
    const item = await this.repository.reserve(input);
    if (!item) {
      throw new InsufficientStockError();
    }
    return item;
  }

  async release(input: StockCommand): Promise<StockItem> {
    ensurePositiveQuantity(input.quantity);
    const item = await this.repository.release(input);
    if (!item) {
      throw new InsufficientReservedStockError();
    }
    return item;
  }

  async confirm(input: StockCommand): Promise<StockItem> {
    ensurePositiveQuantity(input.quantity);
    const item = await this.repository.confirm(input);
    if (!item) {
      throw new InsufficientReservedStockError();
    }
    return item;
  }

  async setAvailable(input: SetAvailableStockCommand): Promise<StockItem> {
    ensureNonNegativeInteger(input.quantity);
    return this.repository.setAvailable(input);
  }
}

function ensurePositiveQuantity(quantity: number): void {
  if (!Number.isInteger(quantity) || quantity <= 0) {
    throw new InvalidStockQuantityError();
  }
}

function ensureNonNegativeInteger(quantity: number): void {
  if (!Number.isInteger(quantity) || quantity < 0) {
    throw new InvalidStockQuantityError();
  }
}
