<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\OpeningStockRepository;
use InvalidArgumentException;
use PDO;
use RuntimeException;

final class OpeningStockService
{
    public function __construct(private PDO $pdo, private OpeningStockRepository $repo) {}

    public function create(array $input): int
    {
        $warehouseId = (int)($input['warehouse_id'] ?? 0);
        if ($warehouseId <= 0) {
            throw new InvalidArgumentException('اختر مخزن');
        }
        return $this->repo->createDoc([
            'doc_no' => $this->repo->nextDocNo(),
            'doc_date' => (string)($input['doc_date'] ?? date('Y-m-d')),
            'warehouse_id' => $warehouseId,
            'notes' => trim((string)($input['notes'] ?? '')) ?: null,
            'created_by' => current_user_id(),
        ]);
    }

    public function addLine(array $input): void
    {
        $docId = (int)($input['doc_id'] ?? 0);
        $itemId = (int)($input['item_id'] ?? 0);
        $qty = (float)($input['qty'] ?? 0);
        if ($docId <= 0 || $itemId <= 0 || $qty <= 0) {
            throw new InvalidArgumentException('بيانات غير مكتملة');
        }
        $unitId = (int)($input['unit_id'] ?? 0);
        $unitId = $unitId > 0 ? $unitId : null;
        $cost = (float)($input['cost'] ?? 0);
        $warehouseId = $this->repo->docWarehouseId($docId);
        if ($this->repo->itemAlreadyOpened($warehouseId, $itemId)) {
            throw new RuntimeException('تم إدخال رصيد افتتاحي لهذا الصنف في هذا المخزن من قبل. استخدم إذن إضافة/تسوية.');
        }
        $this->repo->addLine($docId, $itemId, $unitId, $qty, $cost);
    }

    public function updateLine(array $input): void
    {
        $docId = (int)($input['doc_id'] ?? 0);
        $lineId = (int)($input['line_id'] ?? 0);
        $qty = (float)($input['qty'] ?? 0);
        if ($docId <= 0 || $lineId <= 0 || $qty <= 0) {
            throw new InvalidArgumentException('بيانات غير صحيحة');
        }
        $doc = $this->repo->findDoc($docId);
        if (!$doc || (string)$doc['status'] !== 'DRAFT') {
            throw new RuntimeException('لا يمكن التعديل بعد الترحيل');
        }
        $unitId = (int)($input['unit_id'] ?? 0);
        $unitId = $unitId > 0 ? $unitId : null;
        $cost = (float)($input['cost'] ?? 0);
        $this->repo->updateLine($docId, $lineId, $unitId, $qty, $cost);
    }

    public function deleteDoc(int $docId): void
    {
        $doc = $this->repo->findDoc($docId);
        if (!$doc || strtoupper((string)$doc['status']) !== 'DRAFT') {
            throw new RuntimeException('لا يمكن حذف هذا المستند');
        }
        $this->repo->deleteDraftDoc($docId);
    }

    public function deleteLine(int $docId, int $lineId): void
    {
        if ($docId > 0 && $lineId > 0) {
            $this->repo->deleteLine($docId, $lineId);
        }
    }

    public function post(int $docId): void
    {
        if ($docId <= 0) {
            throw new InvalidArgumentException('مستند غير صحيح');
        }
        $doc = $this->repo->findDoc($docId);
        if (!$doc) throw new RuntimeException('المستند غير موجود');
        if ((string)$doc['status'] !== 'DRAFT') throw new RuntimeException('المستند غير قابل للترحيل');
        $lines = $this->repo->linesForDoc($docId);
        if (!$lines) throw new RuntimeException('أضف أسطر أولاً');

        foreach ($lines as $ln) {
            if ($this->repo->itemAlreadyOpened((int)$doc['warehouse_id'], (int)$ln['item_id'])) {
                throw new RuntimeException('يوجد صنف داخل المستند تم افتتاحه مسبقًا. احذف السطر وأكمل.');
            }
        }

        $this->pdo->beginTransaction();
        try {
            foreach ($lines as $ln) {
                $itemId = (int)$ln['item_id'];
                $qty = (float)$ln['qty'];
                $unitId = (int)($ln['unit_id'] ?? 0);
                $factor = item_unit_factor($this->pdo, $itemId, $unitId > 0 ? $unitId : null);
                $qtyBase = $qty * $factor;
                $cost = (float)$ln['cost'];
                $this->repo->insertStockMove($docId, (int)$doc['warehouse_id'], $itemId, $qtyBase, $cost, current_user_id());
                stock_balance_apply($this->pdo, (int)$doc['warehouse_id'], $itemId, $qtyBase);
            }
            $this->repo->markPosted($docId);
            $this->pdo->commit();
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) $this->pdo->rollBack();
            throw $e;
        }
    }
}
