<?php

declare(strict_types=1);

namespace App\Services;

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

final class ItemService
{
    public function __construct(private PDO $pdo, private ItemRepository $items) {}

    public function create(array $input): int
    {
        $data = $this->normalize($input, false);
        try {
            $this->pdo->beginTransaction();
            $itemId = $this->items->create($data);
            $this->items->ensureMainStockBalance($itemId);
            $this->syncUnits($itemId, $data);
            $this->pdo->commit();
            return $itemId;
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            throw $e;
        }
    }

    public function update(int $id, array $input): void
    {
        if ($id <= 0 || !$this->items->findById($id)) {
            throw new RuntimeException('الصنف غير موجود');
        }
        $data = $this->normalize($input, true);
        try {
            $this->pdo->beginTransaction();
            $this->items->update($id, $data);
            $this->syncUnits($id, $data);
            $this->pdo->commit();
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            throw $e;
        }
    }


    public function delete(int $id): void
    {
        if ($id <= 0 || !$this->items->findById($id)) {
            throw new RuntimeException('الصنف غير موجود');
        }

        $usage = $this->items->usageSummary($id);
        if ($usage !== []) {
            $labels = [
                'sales_items' => 'فواتير المبيعات',
                'purchase_invoice_lines' => 'فواتير المشتريات',
                'purchase_return_lines' => 'مرتجعات الشراء',
                'sales_return_items' => 'مرتجعات البيع',
                'wh_doc_lines' => 'أذون المخازن',
                'stock_moves' => 'حركات مخزنية',
                'stock_balances' => 'أرصدة مخزنية',
                'opening_doc_lines' => 'افتتاحيات مخزون',
                'quotation_items' => 'عروض أسعار',
                'item_units' => 'وحدات الصنف',
            ];
            $parts = [];
            foreach ($usage as $key => $count) {
                $parts[] = ($labels[$key] ?? $key) . ' (' . $count . ')';
            }
            throw new RuntimeException('لا يمكن حذف الصنف لأنه مرتبط بـ: ' . implode('، ', $parts));
        }

        try {
            $this->pdo->beginTransaction();

            if (table_exists($this->pdo, 'stock_balances') && table_has_column($this->pdo, 'stock_balances', 'item_id')) {
                $st = $this->pdo->prepare('SELECT COUNT(*) FROM stock_balances WHERE item_id = ? AND ABS(COALESCE(qty,0)) > 0.000001');
                $st->execute([$id]);
                $nonZeroBalances = (int) ($st->fetchColumn() ?: 0);
                if ($nonZeroBalances > 0) {
                    throw new RuntimeException('لا يمكن حذف الصنف لأن له أرصدة مخزنية فعلية.');
                }

                $st = $this->pdo->prepare('DELETE FROM stock_balances WHERE item_id = ?');
                $st->execute([$id]);
            }
            if (table_exists($this->pdo, 'item_units') && table_has_column($this->pdo, 'item_units', 'item_id')) {
                $st = $this->pdo->prepare('DELETE FROM item_units WHERE item_id = ?');
                $st->execute([$id]);
            }

            $this->items->delete($id);
            $this->pdo->commit();
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            throw $e;
        }
    }

    private function normalize(array $input, bool $isUpdate): array
    {
        $name = trim((string)($input['name'] ?? ''));
        if ($name === '') {
            throw new InvalidArgumentException('اسم الصنف مطلوب');
        }

        $defaultUnitId = (int)($input['default_unit_id'] ?? 0);
        $defaultUnitId = $defaultUnitId > 0 ? $defaultUnitId : null;
        $packUnitId = (int)($input['pack_unit_id'] ?? 0);
        $packUnitId = $packUnitId > 0 ? $packUnitId : null;
        $packFactor = (float)($input['pack_factor'] ?? 0);

        if ($packUnitId && $defaultUnitId && $packUnitId === $defaultUnitId) {
            throw new InvalidArgumentException('الوحدة الإجمالية لا يمكن أن تكون نفس الوحدة الأساسية');
        }
        if ($packUnitId && $defaultUnitId && $packFactor <= 0) {
            throw new InvalidArgumentException('أدخل عدد الوحدات الأساسية داخل الوحدة الإجمالية');
        }

        $supplierId = null;
        if ($this->items->hasSupplierColumn()) {
            $tmp = (int)($input['default_supplier_id'] ?? 0);
            $supplierId = $tmp > 0 ? $tmp : null;
        }

        return [
            'name' => $name,
            'barcode' => trim((string)($input['barcode'] ?? '')) ?: null,
            'cost' => (float)($input['cost'] ?? 0),
            'price' => (float)($input['price'] ?? 0),
            'brand' => trim((string)($input['brand'] ?? '')) ?: null,
            'notes' => trim((string)($input['notes'] ?? '')) ?: null,
            'category_id' => (($cid=(int)($input['category_id'] ?? 0)) > 0 ? $cid : null),
            'default_unit_id' => $defaultUnitId,
            'default_supplier_id' => $supplierId,
            'reorder_point' => (float)($input['reorder_point'] ?? 0),
            'low_stock_level' => (float)($input['low_stock_level'] ?? 0),
            'is_active' => $isUpdate ? (!empty($input['is_active']) ? 1 : 0) : 1,
            'pack_unit_id' => $packUnitId,
            'pack_factor' => $packFactor,
        ];
    }

    private function syncUnits(int $itemId, array $data): void
    {
        if (!empty($data['default_unit_id'])) {
            $this->items->clearBaseItemUnitsExcept($itemId, (int)$data['default_unit_id']);
            $this->items->upsertItemUnit($itemId, (int)$data['default_unit_id'], 1.0, 1);
        } else {
            $this->items->clearItemUnits($itemId);
        }

        $this->items->clearNonBaseItemUnits($itemId);
        if (!empty($data['pack_unit_id']) && !empty($data['default_unit_id'])) {
            $this->items->upsertItemUnit($itemId, (int)$data['pack_unit_id'], (float)$data['pack_factor'], 0);
        }
    }
}
