<?php

namespace App\Domains\Catalog\Models;

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

#[Fillable([
    'sold_units',
    'reserved_stock',
    'real_stock',
])]
class Inventory extends Model
{
    use HasFactory;

    public $timestamps = false;

    protected $table = 'inventories';

    protected $attributes = [
        'sold_units' => 0,
        'reserved_stock' => 0,
        'real_stock' => 0,
    ];

    protected function casts(): array
    {
        return [
            'sold_units' => 'integer',
            'reserved_stock' => 'integer',
            'real_stock' => 'integer',
        ];
    }

    /** @return HasOne<CatalogItem, $this> */
    public function catalogItem(): HasOne
    {
        return $this->hasOne(CatalogItem::class);
    }

    /** @return HasOne<Variant, $this> */
    public function variant(): HasOne
    {
        return $this->hasOne(Variant::class);
    }

    /** @return HasMany<StockReservationLine, $this> */
    public function stockReservationLines(): HasMany
    {
        return $this->hasMany(StockReservationLine::class);
    }

    public function availableStock(): int
    {
        return max(0, $this->real_stock - $this->reserved_stock);
    }

    public function reserve(int $amount, bool $tracksInventory): void
    {
        if ($amount < 0) {
            throw new \InvalidArgumentException('La cantidad a reservar debe ser positiva.');
        }

        if ($tracksInventory && $this->availableStock() < $amount) {
            throw new \InvalidArgumentException('No hay suficiente stock disponible para reservar.');
        }

        $this->reserved_stock += $amount;
        $this->save();
    }

    public function release(int $amount): void
    {
        if ($amount < 0 || $this->reserved_stock < $amount) {
            throw new \InvalidArgumentException('La cantidad reservada no es válida.');
        }

        $this->reserved_stock -= $amount;
        $this->save();
    }

    public function buy(int $amount, bool $tracksInventory): void
    {
        if ($amount < 0 || $this->reserved_stock < $amount) {
            throw new \InvalidArgumentException('La cantidad reservada no alcanza para confirmar la compra.');
        }

        if ($tracksInventory && $this->real_stock < $amount) {
            throw new \InvalidArgumentException('No hay suficiente stock real para confirmar la compra.');
        }

        if ($tracksInventory) {
            $this->real_stock -= $amount;
        }

        $this->reserved_stock -= $amount;
        $this->sold_units += $amount;
        $this->save();
    }
}
