<?php

declare(strict_types=1);

namespace Bot\Infrastructure\Repository\Database;

use Bot\Domain\Entity\Payment;
use Bot\Domain\Repository\PaymentRepositoryInterface;
use PDO;

final class DatabasePaymentRepository implements PaymentRepositoryInterface
{
    public function __construct(
        private readonly PDO $pdo,
    ) {
    }

    public function findById(int $id): ?Payment
    {
        $stmt = $this->pdo->prepare('SELECT * FROM payments WHERE id = :id');
        $stmt->execute(['id' => $id]);
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        return $this->rowToPayment($row);
    }

    public function findByPayload(string $payload): ?Payment
    {
        $stmt = $this->pdo->prepare('SELECT * FROM payments WHERE payload = :payload');
        $stmt->execute(['payload' => $payload]);
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        return $this->rowToPayment($row);
    }

    public function findByExternalId(string $externalId): ?Payment
    {
        $stmt = $this->pdo->prepare('SELECT * FROM payments WHERE external_id = :external_id');
        $stmt->execute(['external_id' => $externalId]);
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        return $this->rowToPayment($row);
    }

    public function save(Payment $payment): void
    {
        $id = $payment->getId();

        if ($id === 0) {
            // Insert
            $stmt = $this->pdo->prepare(
                'INSERT INTO payments (user_id, gateway, amount, status, external_id, payload)
                 VALUES (:user_id, :gateway, :amount, :status, :external_id, :payload)'
            );
            $stmt->execute([
                'user_id' => $payment->getUserId(),
                'gateway' => $payment->getGateway(),
                'amount' => $payment->getAmount(),
                'status' => $payment->getStatus(),
                'external_id' => $payment->getExternalId(),
                'payload' => $payment->getPayload(),
            ]);
        } else {
            // Update
            $stmt = $this->pdo->prepare(
                'UPDATE payments SET
                    user_id = :user_id,
                    gateway = :gateway,
                    amount = :amount,
                    status = :status,
                    external_id = :external_id,
                    payload = :payload
                WHERE id = :id'
            );
            $stmt->execute([
                'id' => $id,
                'user_id' => $payment->getUserId(),
                'gateway' => $payment->getGateway(),
                'amount' => $payment->getAmount(),
                'status' => $payment->getStatus(),
                'external_id' => $payment->getExternalId(),
                'payload' => $payment->getPayload(),
            ]);
        }
    }

    /**
     * @param array<string,mixed> $row
     */
    private function rowToPayment(array $row): Payment
    {
        $payment = new Payment(
            (int) $row['id'],
            (int) $row['user_id'],
            $row['gateway'],
            (int) $row['amount'],
            $row['status'],
            $row['external_id'] ?? null,
            $row['payload'] ?? null,
        );

        return $payment;
    }
}

