<?php

namespace App\Modules\Inventory\Reservation\Repositories;

use App\Modules\Inventory\Reservation\Models\InventoryReservationMovement;
use App\Modules\Inventory\Reservation\Support\ReservationEntryType;
use App\Modules\Inventory\Stock\Support\DecimalQuantity;

class InventoryReservationMovementRepository
{
    /**
     * @param  array<string, mixed>  $attributes
     */
    public function insert(array $attributes): InventoryReservationMovement
    {
        return InventoryReservationMovement::query()->create($attributes);
    }

    /**
     * @return iterable<int, InventoryReservationMovement>
     */
    public function cursorForTenantOrdered(int $tenantId): iterable
    {
        return InventoryReservationMovement::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->orderBy('id')
            ->cursor();
    }

    public function sumOpenQuantity(int $tenantId, string $reservationPublicId): string
    {
        $sum = '0';
        foreach (InventoryReservationMovement::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->where('reservation_public_id', $reservationPublicId)
            ->orderBy('id')
            ->cursor() as $row) {
            $q = (string) $row->quantity;
            $sum = match ($row->entry_type) {
                ReservationEntryType::Reserve => DecimalQuantity::add($sum, $q),
                ReservationEntryType::Release, ReservationEntryType::Consume => DecimalQuantity::add(
                    $sum,
                    DecimalQuantity::negate($q),
                ),
            };
        }

        return $sum;
    }

    /**
     * @return iterable<int, array{tenant_id:int,reservation_public_id:string,warehouse_id:int,item_id:int}>
     */
    public function distinctExpiredReserveHeads(?int $tenantId = null): iterable
    {
        $q = InventoryReservationMovement::withoutGlobalScopes()
            ->where('entry_type', ReservationEntryType::Reserve)
            ->whereNotNull('expires_at')
            ->where('expires_at', '<', now())
            ->orderBy('id');

        if ($tenantId !== null) {
            $q->where('tenant_id', $tenantId);
        }

        $seen = [];
        foreach ($q->cursor() as $row) {
            $rid = (string) $row->reservation_public_id;
            $tid = (int) $row->tenant_id;
            $sig = $tid.'|'.$rid;
            if (isset($seen[$sig])) {
                continue;
            }
            $seen[$sig] = true;

            yield [
                'tenant_id' => $tid,
                'reservation_public_id' => $rid,
                'warehouse_id' => (int) $row->warehouse_id,
                'item_id' => (int) $row->item_id,
            ];
        }
    }
}
