<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Persistence\Repositories;

use ApiModel\Domain\Repository\CurrencyRepositoryInterface;
use ApiModel\Infrastructure\Persistence\Database;
use PDO;

final class PdoCurrencyRepository implements CurrencyRepositoryInterface
{
    public function __construct(private readonly PDO $pdo) {}

    public function findById(string $id): ?array
    {
        $st = $this->pdo->prepare('SELECT * FROM currencies WHERE id = ?');
        $st->execute([$id]);
        $row = $st->fetch();

        return $row !== false ? $row : null;
    }

    public function findByCode(string $code): ?array
    {
        $st = $this->pdo->prepare('SELECT * FROM currencies WHERE UPPER(code) = UPPER(?)');
        $st->execute([$code]);
        $row = $st->fetch();

        return $row !== false ? $row : null;
    }

    public function listAll(?bool $activeOnly = null): array
    {
        if ($activeOnly === true) {
            $st = $this->pdo->query('SELECT * FROM currencies WHERE is_active = TRUE ORDER BY code ASC');

            return $st->fetchAll();
        }

        $st = $this->pdo->query('SELECT * FROM currencies ORDER BY code ASC');

        return $st->fetchAll();
    }

    public function insert(string $id, string $code, string $name, ?string $symbol, int $decimalPlaces): void
    {
        $this->pdo->prepare(
            'INSERT INTO currencies (id, code, name, symbol, decimal_places, is_active)
             VALUES (?, ?, ?, ?, ?, TRUE)'
        )->execute([$id, strtoupper($code), $name, $symbol, $decimalPlaces]);
    }

    public function update(string $id, string $code, string $name, ?string $symbol, int $decimalPlaces, bool $isActive): void
    {
        $this->pdo->prepare(
            'UPDATE currencies
             SET code = ?, name = ?, symbol = ?, decimal_places = ?, is_active = ?, updated_at = CURRENT_TIMESTAMP
             WHERE id = ?'
        )->execute([strtoupper($code), $name, $symbol, $decimalPlaces, Database::bool($isActive), $id]);
    }

    public function delete(string $id): void
    {
        $this->pdo->prepare('DELETE FROM currencies WHERE id = ?')->execute([$id]);
    }

    public function codeExists(string $code, ?string $excludeId = null): bool
    {
        if ($excludeId !== null) {
            $st = $this->pdo->prepare('SELECT 1 FROM currencies WHERE UPPER(code) = UPPER(?) AND id <> ? LIMIT 1');
            $st->execute([$code, $excludeId]);
        } else {
            $st = $this->pdo->prepare('SELECT 1 FROM currencies WHERE UPPER(code) = UPPER(?) LIMIT 1');
            $st->execute([$code]);
        }

        return (bool) $st->fetchColumn();
    }

    public function isActiveCode(string $code): bool
    {
        $st = $this->pdo->prepare('SELECT 1 FROM currencies WHERE UPPER(code) = UPPER(?) AND is_active = TRUE LIMIT 1');
        $st->execute([$code]);

        return (bool) $st->fetchColumn();
    }
}
