<?php

declare(strict_types=1);

namespace App\Modules\Expenses\Application\Services;

use App\Core\AppBootstrap;
use PDO;
use RuntimeException;

final class ExpenseFormService
{
    public function __construct(private PDO $pdo)
    {
    }

    public function ensureSchema(): void
    {
        AppBootstrap::bootExpenses($this->pdo, true);
    }

    /** @return array<string,mixed> */
    public function loadCategoryForm(int $id): array
    {
        $category = [
            'id' => 0,
            'name' => '',
            'code' => '',
            'is_active' => 1,
            'sort_order' => 0,
            'notes' => '',
        ];

        if ($id > 0) {
            $st = $this->pdo->prepare('SELECT * FROM expense_categories WHERE id=?');
            $st->execute([$id]);
            $row = $st->fetch();
            if ($row) {
                $category = array_merge($category, $row);
            }
        }

        return ['category' => $category, 'is_edit' => $id > 0];
    }

    /** @param array<string,mixed> $input */
    public function saveCategory(int $id, array $input): void
    {
        $category = [
            'name' => trim((string) ($input['name'] ?? '')),
            'code' => trim((string) ($input['code'] ?? '')),
            'is_active' => (int) ($input['is_active'] ?? 1),
            'sort_order' => (int) ($input['sort_order'] ?? 0),
            'notes' => trim((string) ($input['notes'] ?? '')),
        ];

        if ($category['name'] === '') {
            throw new RuntimeException('اسم المجموعة مطلوب.');
        }

        $dupSql = 'SELECT id FROM expense_categories WHERE name=?' . ($id > 0 ? ' AND id<>?' : '');
        $dup = $this->pdo->prepare($dupSql);
        $dup->execute($id > 0 ? [$category['name'], $id] : [$category['name']]);
        if ($dup->fetch()) {
            throw new RuntimeException('اسم المجموعة مستخدم من قبل.');
        }

        if ($id > 0) {
            $st = $this->pdo->prepare('UPDATE expense_categories SET name=?, code=?, is_active=?, sort_order=?, notes=? WHERE id=?');
            $st->execute([
                $category['name'],
                $category['code'] !== '' ? $category['code'] : null,
                $category['is_active'],
                $category['sort_order'],
                $category['notes'] !== '' ? $category['notes'] : null,
                $id,
            ]);
            audit_log('UPDATE_EXPENSE_CATEGORY', 'expense_categories', $id, ['name' => $category['name']]);
            return;
        }

        $st = $this->pdo->prepare('INSERT INTO expense_categories (name, code, is_active, sort_order, notes) VALUES (?,?,?,?,?)');
        $st->execute([
            $category['name'],
            $category['code'] !== '' ? $category['code'] : null,
            $category['is_active'],
            $category['sort_order'],
            $category['notes'] !== '' ? $category['notes'] : null,
        ]);
        $newId = (int) $this->pdo->lastInsertId();
        audit_log('CREATE_EXPENSE_CATEGORY', 'expense_categories', $newId, ['name' => $category['name']]);
    }

    /** @return array<string,mixed> */
    public function loadItemForm(int $id, int $categoryId = 0): array
    {
        $categories = $this->pdo->query('SELECT id, name, is_active FROM expense_categories ORDER BY sort_order ASC, name ASC')->fetchAll() ?: [];
        $item = [
            'id' => 0,
            'category_id' => max(0, $categoryId),
            'name' => '',
            'code' => '',
            'is_active' => 1,
            'sort_order' => 0,
            'notes' => '',
        ];

        if ($id > 0) {
            $st = $this->pdo->prepare('SELECT * FROM expense_items WHERE id=?');
            $st->execute([$id]);
            $row = $st->fetch();
            if ($row) {
                $item = array_merge($item, $row);
            }
        }

        return ['item' => $item, 'categories' => $categories, 'is_edit' => $id > 0];
    }

    /** @param array<string,mixed> $input */
    public function saveItem(int $id, array $input): void
    {
        $item = [
            'category_id' => (int) ($input['category_id'] ?? 0),
            'name' => trim((string) ($input['name'] ?? '')),
            'code' => trim((string) ($input['code'] ?? '')),
            'is_active' => (int) ($input['is_active'] ?? 1),
            'sort_order' => (int) ($input['sort_order'] ?? 0),
            'notes' => trim((string) ($input['notes'] ?? '')),
        ];

        if ($item['category_id'] <= 0) {
            throw new RuntimeException('مجموعة المصروف مطلوبة.');
        }
        if ($item['name'] === '') {
            throw new RuntimeException('اسم بند المصروف مطلوب.');
        }

        $dupSql = 'SELECT id FROM expense_items WHERE category_id=? AND name=?' . ($id > 0 ? ' AND id<>?' : '');
        $dup = $this->pdo->prepare($dupSql);
        $dup->execute($id > 0 ? [$item['category_id'], $item['name'], $id] : [$item['category_id'], $item['name']]);
        if ($dup->fetch()) {
            throw new RuntimeException('اسم بند المصروف مستخدم داخل هذه المجموعة.');
        }

        if ($id > 0) {
            $st = $this->pdo->prepare('UPDATE expense_items SET category_id=?, name=?, code=?, is_active=?, sort_order=?, notes=? WHERE id=?');
            $st->execute([
                $item['category_id'],
                $item['name'],
                $item['code'] !== '' ? $item['code'] : null,
                $item['is_active'],
                $item['sort_order'],
                $item['notes'] !== '' ? $item['notes'] : null,
                $id,
            ]);
            audit_log('UPDATE_EXPENSE_ITEM', 'expense_items', $id, ['name' => $item['name']]);
            return;
        }

        $st = $this->pdo->prepare('INSERT INTO expense_items (category_id, name, code, is_active, sort_order, notes) VALUES (?,?,?,?,?,?)');
        $st->execute([
            $item['category_id'],
            $item['name'],
            $item['code'] !== '' ? $item['code'] : null,
            $item['is_active'],
            $item['sort_order'],
            $item['notes'] !== '' ? $item['notes'] : null,
        ]);
        $newId = (int) $this->pdo->lastInsertId();
        audit_log('CREATE_EXPENSE_ITEM', 'expense_items', $newId, ['name' => $item['name']]);
    }
}
