<?php

declare(strict_types=1);

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

    public function findByPath(string $slug): ?array
    {
        $path = myronNormalizePath($slug);
        $statement = $this->pdo->prepare('SELECT * FROM disabled_page_redirects WHERE slug = :slug LIMIT 1');
        $statement->execute([':slug' => $path]);
        $row = $statement->fetch(PDO::FETCH_ASSOC);

        return is_array($row) ? $this->hydrate($row) : null;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listForBundle(string $bundleId): array
    {
        $statement = $this->pdo->prepare(
            'SELECT *
             FROM disabled_page_redirects
             WHERE bundle_id = :bundle_id
             ORDER BY slug ASC'
        );
        $statement->execute([':bundle_id' => trim($bundleId)]);

        return array_values(array_map(
            fn (array $row): array => $this->hydrate($row),
            array_filter($statement->fetchAll(PDO::FETCH_ASSOC), 'is_array')
        ));
    }

    /**
     * @param list<array<string, mixed>> $entries
     */
    public function insertBatch(array $entries, string $auditId): void
    {
        if ($entries === []) {
            return;
        }

        $statement = $this->pdo->prepare(
            'INSERT INTO disabled_page_redirects (slug, bundle_id, fallback_url, audit_id, created_at)
             VALUES (:slug, :bundle_id, :fallback_url, :audit_id, :created_at)'
        );
        $now = myronNow();
        foreach ($entries as $entry) {
            $statement->execute([
                ':slug' => myronNormalizePath((string) ($entry['slug'] ?? '')),
                ':bundle_id' => trim((string) ($entry['bundle_id'] ?? '')),
                ':fallback_url' => $this->normalizeFallback((string) ($entry['fallback_url'] ?? '/')),
                ':audit_id' => trim($auditId),
                ':created_at' => (string) ($entry['created_at'] ?? $now),
            ]);
        }
    }

    public function deleteForBundle(string $bundleId): int
    {
        $statement = $this->pdo->prepare('DELETE FROM disabled_page_redirects WHERE bundle_id = :bundle_id');
        $statement->execute([':bundle_id' => trim($bundleId)]);
        return $statement->rowCount();
    }

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

    public function exists(string $slug): bool
    {
        return $this->findByPath($slug) !== null;
    }

    private function normalizeFallback(string $fallback): string
    {
        $trimmed = trim($fallback) ?: '/';
        if (preg_match('#^https?://#i', $trimmed) === 1 || str_starts_with($trimmed, '//')) {
            throw new InvalidArgumentException('Redirect fallback must be a local published page path.');
        }

        return myronNormalizePath($trimmed);
    }

    /**
     * @param array<string, mixed> $row
     * @return array<string, mixed>
     */
    private function hydrate(array $row): array
    {
        return [
            'slug' => (string) ($row['slug'] ?? ''),
            'bundle_id' => (string) ($row['bundle_id'] ?? ''),
            'fallback_url' => (string) ($row['fallback_url'] ?? '/'),
            'audit_id' => (string) ($row['audit_id'] ?? ''),
            'created_at' => (string) ($row['created_at'] ?? ''),
        ];
    }
}
