<?php

declare(strict_types=1);

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

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

    public function create(array $data): array
    {
        $id = 'fsub_' . bin2hex(random_bytes(8));
        $statement = $this->pdo->prepare(
            'INSERT INTO form_submissions (id, form_id, submitted_at, fields_json, source_url, ip_hash, user_agent)
             VALUES (:id, :form_id, :submitted_at, :fields_json, :source_url, :ip_hash, :user_agent)'
        );
        $statement->execute([
            ':id' => $id,
            ':form_id' => (string) ($data['form_id'] ?? ''),
            ':submitted_at' => myronNow(),
            ':fields_json' => json_encode(is_array($data['fields'] ?? null) ? $data['fields'] : [], JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES),
            ':source_url' => substr((string) ($data['source_url'] ?? ''), 0, 500),
            ':ip_hash' => (string) ($data['ip_hash'] ?? ''),
            ':user_agent' => substr((string) ($data['user_agent'] ?? ''), 0, 500),
        ]);
        return $this->findById($id) ?? [];
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listForForm(string $formId, int $limit = 50, int $offset = 0): array
    {
        $statement = $this->pdo->prepare(
            'SELECT * FROM form_submissions WHERE form_id = :form_id ORDER BY submitted_at DESC LIMIT :limit OFFSET :offset'
        );
        $statement->bindValue(':form_id', trim($formId));
        $statement->bindValue(':limit', max(1, min(50, $limit)), PDO::PARAM_INT);
        $statement->bindValue(':offset', max(0, $offset), PDO::PARAM_INT);
        $statement->execute();
        return array_map([$this, 'hydrate'], $statement->fetchAll() ?: []);
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listRecentAcrossForms(int $limit = 5): array
    {
        $statement = $this->pdo->prepare(
            'SELECT fs.*, fd.name AS form_name
             FROM form_submissions fs
             LEFT JOIN form_definitions fd ON fd.id = fs.form_id
             ORDER BY fs.submitted_at DESC
             LIMIT :limit'
        );
        $statement->bindValue(':limit', max(1, min(50, $limit)), PDO::PARAM_INT);
        $statement->execute();
        return array_map([$this, 'hydrate'], $statement->fetchAll() ?: []);
    }

    public function delete(string $id): bool
    {
        $statement = $this->pdo->prepare('DELETE FROM form_submissions WHERE id = :id');
        $statement->execute([':id' => trim($id)]);
        return $statement->rowCount() > 0;
    }

    public function countTotal(?string $since = null): int
    {
        if ($since === null) {
            return (int) $this->pdo->query('SELECT COUNT(*) FROM form_submissions')->fetchColumn();
        }
        $statement = $this->pdo->prepare('SELECT COUNT(*) FROM form_submissions WHERE submitted_at >= :since');
        $statement->execute([':since' => $since]);
        return (int) $statement->fetchColumn();
    }

    public function countForForm(string $formId): int
    {
        $statement = $this->pdo->prepare('SELECT COUNT(*) FROM form_submissions WHERE form_id = :form_id');
        $statement->execute([':form_id' => trim($formId)]);
        return (int) $statement->fetchColumn();
    }

    /**
     * @param array<string, mixed> $row
     * @return array<string, mixed>
     */
    private function hydrate(array $row): array
    {
        $fields = json_decode((string) ($row['fields_json'] ?? '{}'), true);
        return [
            'id' => (string) ($row['id'] ?? ''),
            'form_id' => (string) ($row['form_id'] ?? ''),
            'form_name' => (string) ($row['form_name'] ?? ''),
            'submitted_at' => (string) ($row['submitted_at'] ?? ''),
            'fields' => is_array($fields) ? $fields : [],
            'source_url' => (string) ($row['source_url'] ?? ''),
            'ip_hash' => (string) ($row['ip_hash'] ?? ''),
            'user_agent' => (string) ($row['user_agent'] ?? ''),
        ];
    }
}
