<?php

namespace App\Services;

use App\Models\Product;
use App\Models\ProductStock;
use App\Models\StockMutation;
use App\Models\StockTransfer;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class StockService
{
    public function assertAvailable(int $branchId, Product $product, float $quantity): void
    {
        if (! $product->track_stock || $product->type !== 'retail') {
            return;
        }

        $stock = ProductStock::query()
            ->where('branch_id', $branchId)
            ->where('product_id', $product->id)
            ->lockForUpdate()
            ->first();

        if (! $stock || (float) $stock->quantity < $quantity) {
            throw ValidationException::withMessages([
                'stock' => "Stok {$product->name} tidak cukup.",
            ]);
        }
    }

    public function decrease(int $branchId, Product $product, float $quantity, string $sourceType, ?int $sourceId, ?User $user = null): void
    {
        if (! $product->track_stock || $product->type !== 'retail') {
            return;
        }

        $this->assertAvailable($branchId, $product, $quantity);
        $stock = ProductStock::query()->firstOrCreate(
            ['branch_id' => $branchId, 'product_id' => $product->id],
            ['quantity' => 0],
        );
        $stock->decrement('quantity', $quantity);
        $stock->refresh();
        $this->log($branchId, $product->id, -abs($quantity), (float) $stock->quantity, $sourceType, $sourceId, $user);
    }

    public function increase(int $branchId, Product $product, float $quantity, string $sourceType, ?int $sourceId, ?User $user = null): void
    {
        if (! $product->track_stock || $product->type !== 'retail') {
            return;
        }

        $stock = ProductStock::query()->firstOrCreate(
            ['branch_id' => $branchId, 'product_id' => $product->id],
            ['quantity' => 0],
        );
        $stock->increment('quantity', $quantity);
        $stock->refresh();
        $this->log($branchId, $product->id, abs($quantity), (float) $stock->quantity, $sourceType, $sourceId, $user);
    }

    public function approveTransfer(StockTransfer $transfer, User $user): StockTransfer
    {
        return DB::transaction(function () use ($transfer, $user): StockTransfer {
            $transfer = StockTransfer::query()->with('items')->lockForUpdate()->findOrFail($transfer->id);

            if ($transfer->status !== 'pending') {
                throw ValidationException::withMessages(['status' => 'Transfer tidak lagi pending.']);
            }

            foreach ($transfer->items as $item) {
                $product = Product::query()->lockForUpdate()->findOrFail($item->product_id);
                $this->decrease($transfer->from_branch_id, $product, (float) $item->quantity, 'stock_transfer_out', $transfer->id, $user);
                $this->increase($transfer->to_branch_id, $product, (float) $item->quantity, 'stock_transfer_in', $transfer->id, $user);
            }

            $transfer->update([
                'status' => 'approved',
                'approved_by' => $user->id,
                'approved_at' => now(),
            ]);

            return $transfer;
        });
    }

    private function log(int $branchId, int $productId, float $change, float $after, string $sourceType, ?int $sourceId, ?User $user): void
    {
        StockMutation::query()->create([
            'branch_id' => $branchId,
            'product_id' => $productId,
            'user_id' => $user?->id,
            'source_type' => $sourceType,
            'source_id' => $sourceId,
            'quantity_change' => $change,
            'quantity_after' => $after,
        ]);
    }
}
