<?php

namespace App\Services;

use App\Models\Order;
use App\Models\Product;
use App\Models\StockLedger;
use App\Models\StockMovement;
use App\Models\VariantStockMovement;
use Illuminate\Support\Facades\Log;

/**
 * Location-aware cancel/return restock helper used by InventoryService.
 */
class OrderLocationRestock
{
    public function __construct(protected LocationInventoryService $locationInventory)
    {
    }

    public function restock(Order $order, string $reason): void
    {
        $order->loadMissing(['items', 'allocations.items']);
        $restockNote = "Order #{$order->id} {$reason}";
        $createdBy = auth()->id() ?? 1;
        $ledgerType = $reason === 'returned' ? StockLedger::TYPE_RETURN : StockLedger::TYPE_RESTOCK;

        foreach ($order->items as $item) {
            if (!$item->product_id) {
                continue;
            }

            $product = Product::lockForUpdate()->find($item->product_id);
            if (!$product) {
                continue;
            }

            $qtyToRestock = $this->quantityToRestock($product->id, $order->id);
            if ($qtyToRestock <= 0) {
                continue;
            }

            foreach ($this->resolveLocations($order, $item, $qtyToRestock) as $locationId => $qty) {
                if ($qty <= 0) {
                    continue;
                }

                $this->locationInventory->applyMovement(
                    locationId: (int) $locationId,
                    productId: (int) $product->id,
                    type: $ledgerType,
                    quantity: (int) $qty,
                    notes: $restockNote,
                    referenceType: 'order',
                    referenceId: (int) $order->id,
                    createdBy: $createdBy,
                    dualWriteLegacy: true,
                );

                Log::info('Order location restock movement created', [
                    'order_id' => $order->id,
                    'product_id' => $product->id,
                    'location_id' => $locationId,
                    'quantity' => $qty,
                    'reason' => $reason,
                ]);
            }
        }
    }

    protected function quantityToRestock(int $productId, int $orderId): int
    {
        $soldLedger = abs((int) StockLedger::query()
            ->where('product_id', $productId)
            ->where('reference_type', 'order')
            ->where('reference_id', $orderId)
            ->where('type', StockLedger::TYPE_SALE)
            ->sum('quantity'));

        $restockedLedger = (int) StockLedger::query()
            ->where('product_id', $productId)
            ->where('reference_type', 'order')
            ->where('reference_id', $orderId)
            ->whereIn('type', [StockLedger::TYPE_RESTOCK, StockLedger::TYPE_RETURN])
            ->sum('quantity');

        if ($soldLedger > 0 || $restockedLedger > 0) {
            return max(0, $soldLedger - $restockedLedger);
        }

        $patterns = [
            "Order #{$orderId}",
            "POS Order #{$orderId}",
            "POS Order #{$orderId} (Synced)",
        ];
        $prefix = "Order #{$orderId}";

        $sold = abs((int) StockMovement::where('product_id', $productId)->where('type', StockMovement::TYPE_SALE)->whereIn('notes', $patterns)->sum('quantity'))
            + abs((int) VariantStockMovement::where('product_id', $productId)->where('type', VariantStockMovement::TYPE_SALE)->whereIn('notes', $patterns)->sum('quantity'));

        $restocked = (int) StockMovement::where('product_id', $productId)->where('type', StockMovement::TYPE_RESTOCK)->where('notes', 'like', $prefix . '%')->sum('quantity')
            + (int) VariantStockMovement::where('product_id', $productId)->where('type', VariantStockMovement::TYPE_RESTOCK)->where('notes', 'like', $prefix . '%')->sum('quantity');

        return max(0, $sold - $restocked);
    }

    /**
     * @return array<int, int>
     */
    protected function resolveLocations(Order $order, $item, int $qtyToRestock): array
    {
        $locationQuantities = [];

        foreach ($order->allocations as $allocation) {
            foreach ($allocation->items as $allocItem) {
                if ((int) $allocItem->product_id !== (int) $item->product_id) {
                    continue;
                }
                $locId = (int) $allocation->location_id;
                $locationQuantities[$locId] = ($locationQuantities[$locId] ?? 0) + (int) $allocItem->quantity;
            }
        }

        if ($locationQuantities === []) {
            $locId = (int) (
                $item->allocated_location_id
                ?? $order->fulfillment_location_id
                ?? $this->locationInventory->defaultLocationId()
            );

            return [$locId => $qtyToRestock];
        }

        $allocatedTotal = array_sum($locationQuantities);
        if ($allocatedTotal <= 0) {
            $locId = (int) ($order->fulfillment_location_id ?? $this->locationInventory->defaultLocationId());

            return [$locId => $qtyToRestock];
        }

        if ($allocatedTotal === $qtyToRestock) {
            return $locationQuantities;
        }

        $scaled = [];
        $remaining = $qtyToRestock;
        $keys = array_keys($locationQuantities);
        foreach ($keys as $index => $locId) {
            if ($index === count($keys) - 1) {
                $scaled[$locId] = $remaining;
                break;
            }
            $share = (int) floor(($locationQuantities[$locId] / $allocatedTotal) * $qtyToRestock);
            $scaled[$locId] = $share;
            $remaining -= $share;
        }

        return $scaled;
    }
}
