<?php
/*
 * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * See the LICENSE file in the project root for the full license text.
 */

declare(strict_types=1);

namespace App\Tests\Repositories;

use App\Repositories\AuditRepository;
use App\Services\AuditLogger;
use App\Tests\TestCase;
use InvalidArgumentException;

/**
 * R01-N11: AuditRepository::distinctColumn interpolates its argument into
 * SQL. The method is private and both internal callers pass literals, but
 * the runtime whitelist guard makes the contract explicit so a future
 * refactor can't open an injection vector.
 */
final class AuditRepositoryTest extends TestCase
{
    public function testDistinctActionsReturnsSortedUniqueValues(): void
    {
        $pdo    = $this->makeDb();
        $logger = new AuditLogger($pdo);
        $logger->record('UPDATE', 'worker', 1, ['n' => 1], ['n' => 2]);
        $logger->record('CREATE', 'worker', 2, null, ['n' => 1]);
        $logger->record('UPDATE', 'sprint', 3, ['n' => 1], ['n' => 2]);

        $repo = new AuditRepository($pdo);
        $this->assertSame(['CREATE', 'UPDATE'], $repo->distinctActions());
    }

    public function testDistinctEntityTypesReturnsSortedUniqueValues(): void
    {
        $pdo    = $this->makeDb();
        $logger = new AuditLogger($pdo);
        $logger->record('UPDATE', 'worker', 1, ['n' => 1], ['n' => 2]);
        $logger->record('UPDATE', 'sprint', 2, ['n' => 1], ['n' => 2]);
        $logger->record('UPDATE', 'worker', 3, ['n' => 1], ['n' => 2]);

        $repo = new AuditRepository($pdo);
        $this->assertSame(['sprint', 'worker'], $repo->distinctEntityTypes());
    }

    public function testDistinctColumnRejectsUnknownColumnViaReflection(): void
    {
        $pdo  = $this->makeDb();
        $repo = new AuditRepository($pdo);

        $rm = new \ReflectionMethod($repo, 'distinctColumn');
        $rm->setAccessible(true);

        $this->expectException(InvalidArgumentException::class);
        $rm->invoke($repo, 'user_email');
    }

    public function testDistinctColumnRejectsInjectionAttemptViaReflection(): void
    {
        $pdo  = $this->makeDb();
        $repo = new AuditRepository($pdo);

        $rm = new \ReflectionMethod($repo, 'distinctColumn');
        $rm->setAccessible(true);

        $this->expectException(InvalidArgumentException::class);
        $rm->invoke($repo, 'action; DROP TABLE audit_log; --');
    }
}
