<?php

declare(strict_types=1);

namespace App\Services;

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

final class PartyService
{
    public function __construct(
        private PDO $pdo,
        private PartyRepository $parties,
    ) {
    }

    public function create(array $input, ?int $currentUserId): int
    {
        $data = $this->normalize($input);
        try {
            $this->pdo->beginTransaction();
            $partyId = $this->parties->create($data + ['created_by' => $currentUserId ?: null]);
            if ($data['code'] === null) {
                party_auto_code($this->pdo, $partyId);
            }
            $this->pdo->commit();
            return $partyId;
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            throw $e;
        }
    }

    public function update(int $id, array $input): void
    {
        if ($id <= 0) {
            throw new InvalidArgumentException('طرف غير صالح');
        }
        if (!$this->parties->findById($id)) {
            throw new RuntimeException('الطرف غير موجود');
        }

        $data = $this->normalize($input);
        try {
            $this->pdo->beginTransaction();
            $this->parties->update($id, $data);
            if ($data['code'] === null) {
                party_auto_code($this->pdo, $id);
            }
            $this->pdo->commit();
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            throw $e;
        }
    }


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

        $usage = $this->parties->usageSummary($id);
        if ($usage !== []) {
            $labels = [
                'sales_invoices' => 'فواتير مبيعات',
                'purchase_invoices' => 'فواتير مشتريات',
                'sales_returns' => 'مرتجعات بيع',
                'purchase_returns' => 'مرتجعات شراء',
                'party_ledger' => 'كشف حساب',
                'customer_receipts' => 'سندات قبض',
                'supplier_payments' => 'سندات سداد مورد',
                'checks_drawer' => 'شيكات مسحوبة من الطرف',
                'checks_holder' => 'شيكات بحيازة الطرف',
                'checks_endorsed' => 'شيكات مظهّرة للطرف',
                'check_movements' => 'حركات شيكات',
                'quotations' => 'عروض أسعار',
                'items_default_supplier' => 'أصناف مرتبطة كمورد افتراضي',
            ];
            $parts = [];
            foreach ($usage as $key => $count) {
                $parts[] = ($labels[$key] ?? $key) . ' (' . $count . ')';
            }
            throw new RuntimeException('لا يمكن حذف الطرف لأنه مرتبط بـ: ' . implode('، ', $parts));
        }

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

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

        $isCustomer = !empty($input['is_customer']) ? 1 : 0;
        $isSupplier = !empty($input['is_supplier']) ? 1 : 0;
        if ($isCustomer !== 1 && $isSupplier !== 1) {
            throw new InvalidArgumentException('يجب اختيار صفة واحدة على الأقل: عميل أو مورد.');
        }

        $nullOrTrim = static function (mixed $value): ?string {
            $v = trim((string)$value);
            return $v === '' ? null : $v;
        };

        return [
            'code' => $nullOrTrim($input['code'] ?? ''),
            'name' => $name,
            'phone' => $nullOrTrim($input['phone'] ?? ''),
            'phone2' => $nullOrTrim($input['phone2'] ?? ''),
            'email' => $nullOrTrim($input['email'] ?? ''),
            'address' => $nullOrTrim($input['address'] ?? ''),
            'tax_no' => $nullOrTrim($input['tax_no'] ?? ''),
            'notes' => $nullOrTrim($input['notes'] ?? ''),
            'opening_balance' => (float)($input['opening_balance'] ?? 0),
            'credit_limit' => (float)($input['credit_limit'] ?? 0),
            'is_customer' => $isCustomer,
            'is_supplier' => $isSupplier,
            'is_active' => !empty($input['is_active']) ? 1 : 0,
        ];
    }
}
