<?php

declare(strict_types=1);

namespace App\Service;

use App\Entity\DrinkType;
use App\Enum\SystemSettingKey;
use App\Repository\DrinkTypeRepository;
use App\Repository\InventoryRecordRepository;
use App\Repository\OrderRepository;
use App\Repository\SystemConfigRepository;
use App\ValueObject\StockAdjustmentProposal;

readonly class StockAdjustmentService
{
    public function __construct(
        private DrinkTypeRepository $drinkTypeRepository,
        private InventoryRecordRepository $inventoryRecordRepository,
        private OrderRepository $orderRepository,
        private SystemConfigRepository $systemConfigRepository,
    ) {}

    /**
     * Proposes adjusted stock levels for all drink types
     *
     * @return array<int, StockAdjustmentProposal> Array of stock adjustment proposals
     */
    public function proposeStockAdjustments(): array
    {
        $drinkTypes = $this->drinkTypeRepository->findAll();
        $proposals = [];

        foreach ($drinkTypes as $drinkType) {
            $proposals[] = $this->proposeStockAdjustmentForDrinkType($drinkType);
        }

        return $proposals;
    }

    /**
     * Proposes an adjusted stock level for a specific drink type
     */
    public function proposeStockAdjustmentForDrinkType(DrinkType $drinkType): StockAdjustmentProposal
    {
        $currentDesiredStock = $drinkType->getDesiredStock();
        $lookbackOrders =
            (int) $this->systemConfigRepository->getValue(SystemSettingKey::STOCK_ADJUSTMENT_LOOKBACK_ORDERS);
        $increaseAmount = (int) $this->systemConfigRepository->getValue(SystemSettingKey::STOCK_INCREASE_AMOUNT);
        $decreaseAmount = (int) $this->systemConfigRepository->getValue(SystemSettingKey::STOCK_DECREASE_AMOUNT);

        // Get the last N orders for this drink type
        $lastOrders = $this->orderRepository->findLastOrdersForDrinkType($drinkType, $lookbackOrders);

        // If there are no orders, return the current desired stock
        if ($lastOrders === []) {
            return new StockAdjustmentProposal($drinkType, $currentDesiredStock);
        }

        // Check if stock was 0 in the last order
        $lastOrder = $lastOrders[0];
        $lastOrderItems = $lastOrder->getOrderItems();
        $stockWasZeroInLastOrder = false;

        foreach ($lastOrderItems as $orderItem) {
            if ($orderItem->getDrinkType()->getId() === $drinkType->getId()) {
                // Find the inventory record closest to the order creation date
                $inventoryRecords = $this->inventoryRecordRepository->findByDrinkType($drinkType);
                foreach ($inventoryRecords as $record) {
                    if ($record->getTimestamp() <= $lastOrder->getCreatedAt()) {
                        if ($record->getQuantity() === 0) {
                            $stockWasZeroInLastOrder = true;
                        }
                        break;
                    }
                }
                break;
            }
        }

        // If stock was 0 in the last order, increase desired stock
        if ($stockWasZeroInLastOrder) {
            return new StockAdjustmentProposal($drinkType, $currentDesiredStock + $increaseAmount);
        }

        // Check if stock was above zero in all lookback orders
        $stockWasAboveZeroInAllOrders = true;
        $ordersToCheck = min(count($lastOrders), $lookbackOrders);

        for ($i = 0; $i < $ordersToCheck; $i++) {
            $order = $lastOrders[$i];
            $orderItems = $order->getOrderItems();

            foreach ($orderItems as $orderItem) {
                if ($orderItem->getDrinkType()->getId() === $drinkType->getId()) {
                    // Find the inventory record closest to the order creation date
                    $inventoryRecords = $this->inventoryRecordRepository->findByDrinkType($drinkType);
                    foreach ($inventoryRecords as $record) {
                        if ($record->getTimestamp() <= $order->getCreatedAt()) {
                            if ($record->getQuantity() === 0) {
                                $stockWasAboveZeroInAllOrders = false;
                            }
                            break;
                        }
                    }
                    break;
                }
            }

            if (!$stockWasAboveZeroInAllOrders) {
                break;
            }
        }

        // If stock was above zero in all lookback orders, decrease desired stock
        if ($stockWasAboveZeroInAllOrders && $ordersToCheck === $lookbackOrders) {
            $proposedStock = max(0, $currentDesiredStock - $decreaseAmount);
            return new StockAdjustmentProposal($drinkType, $proposedStock);
        }

        // Otherwise, keep the current desired stock
        return new StockAdjustmentProposal($drinkType, $currentDesiredStock);
    }
}
