<?php

declare(strict_types=1);

namespace App\Tests\Integration\Admin;

use App\Domain\Auth\Role;
use App\Domain\Auth\TokenKind;
use App\Domain\Settings\AppSettings;
use App\Tests\Integration\Support\AppTestCase;

final class AppSettingsControllerTest extends AppTestCase
{
    public function testGetReturnsCurrentSnapshotAsBooleans(): void
    {
        $token = $this->createToken(TokenKind::Admin, role: Role::Admin);

        $resp = $this->request('GET', '/api/v1/admin/app-settings', [
            'Authorization' => 'Bearer ' . $token,
        ]);
        self::assertSame(200, $resp->getStatusCode());
        $body = $this->decode($resp);
        self::assertTrue($body['audit_report_received_enabled']);
        self::assertTrue($body['audit_blocklist_request_enabled']);
    }

    public function testNonAdminRoleIsRejected(): void
    {
        $token = $this->createToken(TokenKind::Admin, role: Role::Operator);

        $resp = $this->request('GET', '/api/v1/admin/app-settings', [
            'Authorization' => 'Bearer ' . $token,
        ]);
        self::assertSame(403, $resp->getStatusCode());
    }

    public function testPatchPersistsToggleAndEmitsAudit(): void
    {
        $token = $this->createToken(TokenKind::Admin, role: Role::Admin);

        $resp = $this->request(
            'PATCH',
            '/api/v1/admin/app-settings',
            ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
            (string) json_encode(['audit_report_received_enabled' => false]),
        );
        self::assertSame(200, $resp->getStatusCode());
        $body = $this->decode($resp);
        self::assertFalse($body['audit_report_received_enabled']);
        self::assertTrue($body['audit_blocklist_request_enabled']);

        /** @var AppSettings $settings */
        $settings = $this->container->get(AppSettings::class);
        self::assertFalse($settings->getBool(AppSettings::KEY_AUDIT_REPORT_RECEIVED_ENABLED, true));

        $row = $this->db->fetchAssociative(
            "SELECT details_json FROM audit_log WHERE action = 'app_settings.updated' ORDER BY id DESC LIMIT 1"
        );
        self::assertIsArray($row);
        $details = json_decode((string) $row['details_json'], true);
        self::assertIsArray($details);
        self::assertArrayHasKey('audit_report_received_enabled', $details['changes']);
        self::assertSame(true, $details['changes']['audit_report_received_enabled']['from']);
        self::assertSame(false, $details['changes']['audit_report_received_enabled']['to']);
    }

    public function testPatchWithNoChangesDoesNotEmitAudit(): void
    {
        $token = $this->createToken(TokenKind::Admin, role: Role::Admin);

        $resp = $this->request(
            'PATCH',
            '/api/v1/admin/app-settings',
            ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
            (string) json_encode(['audit_report_received_enabled' => true]),
        );
        self::assertSame(200, $resp->getStatusCode());

        $count = (int) $this->db->fetchOne(
            "SELECT COUNT(*) FROM audit_log WHERE action = 'app_settings.updated'"
        );
        self::assertSame(0, $count);
    }

    public function testPatchValidatesBooleanShape(): void
    {
        $token = $this->createToken(TokenKind::Admin, role: Role::Admin);

        $resp = $this->request(
            'PATCH',
            '/api/v1/admin/app-settings',
            ['Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json'],
            (string) json_encode(['audit_report_received_enabled' => 'maybe']),
        );
        self::assertSame(400, $resp->getStatusCode());
    }
}
