<?php

declare(strict_types=1);

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

    public function record(array $data): array
    {
        $id = $this->generateId();
        $statement = $this->pdo->prepare(
            'INSERT INTO blog_comment_moderation_events (
                id, comment_id, action, from_status, to_status, reason, actor_id, created_at
             ) VALUES (
                :id, :comment_id, :action, :from_status, :to_status, :reason, :actor_id, :created_at
             )'
        );
        $statement->execute([
            ':id' => $id,
            ':comment_id' => trim((string) ($data['comment_id'] ?? '')),
            ':action' => trim((string) ($data['action'] ?? '')),
            ':from_status' => trim((string) ($data['from_status'] ?? '')),
            ':to_status' => trim((string) ($data['to_status'] ?? '')),
            ':reason' => trim((string) ($data['reason'] ?? '')),
            ':actor_id' => $this->nullableString($data['actor_id'] ?? null),
            ':created_at' => myronNow(),
        ]);
        return $this->findById($id) ?? [];
    }

    public function findById(string $id): ?array
    {
        $statement = $this->pdo->prepare('SELECT * FROM blog_comment_moderation_events WHERE id = :id LIMIT 1');
        $statement->execute([':id' => trim($id)]);
        $row = $statement->fetch(PDO::FETCH_ASSOC);
        return is_array($row) ? $this->hydrate($row) : null;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listForComment(string $commentId): array
    {
        $statement = $this->pdo->prepare(
            'SELECT * FROM blog_comment_moderation_events WHERE comment_id = :comment_id ORDER BY created_at ASC, id ASC'
        );
        $statement->execute([':comment_id' => trim($commentId)]);
        return array_map([$this, 'hydrate'], $statement->fetchAll(PDO::FETCH_ASSOC) ?: []);
    }

    private function generateId(): string
    {
        do {
            $id = 'bcme_' . bin2hex(random_bytes(8));
        } while ($this->findById($id) !== null);
        return $id;
    }

    private function nullableString(mixed $value): ?string
    {
        $value = trim((string) ($value ?? ''));
        return $value === '' ? null : $value;
    }

    private function hydrate(array $row): array
    {
        return [
            'id' => (string) ($row['id'] ?? ''),
            'comment_id' => (string) ($row['comment_id'] ?? ''),
            'action' => (string) ($row['action'] ?? ''),
            'from_status' => (string) ($row['from_status'] ?? ''),
            'to_status' => (string) ($row['to_status'] ?? ''),
            'reason' => (string) ($row['reason'] ?? ''),
            'actor_id' => (string) ($row['actor_id'] ?? ''),
            'created_at' => (string) ($row['created_at'] ?? ''),
        ];
    }
}
