<?php

namespace MintyPHP\Tests\Module\Audit\Providers;

use MintyPHP\Module\Audit\Providers\AuditSearchResourceProvider;
use PHPUnit\Framework\TestCase;

class AuditSearchResourceProviderTest extends TestCase
{
    private AuditSearchResourceProvider $provider;

    protected function setUp(): void
    {
        $this->provider = new AuditSearchResourceProvider();
    }

    public function testResourcesReturnsBothAuditKeys(): void
    {
        $resources = $this->provider->resources();

        $this->assertArrayHasKey('api-audit', $resources);
        $this->assertArrayHasKey('system-audit', $resources);
        $this->assertCount(2, $resources);
    }

    public function testResourcesContainRequiredSqlKeys(): void
    {
        foreach ($this->provider->resources() as $key => $resource) {
            $this->assertArrayHasKey('label', $resource, "Resource '{$key}' missing label");
            $this->assertArrayHasKey('permission', $resource, "Resource '{$key}' missing permission");
            $this->assertArrayHasKey('count_sql', $resource, "Resource '{$key}' missing count_sql");
            $this->assertArrayHasKey('preview_sql', $resource, "Resource '{$key}' missing preview_sql");
            $this->assertArrayHasKey('result_sql', $resource, "Resource '{$key}' missing result_sql");
        }
    }

    public function testResourcePermissionKeys(): void
    {
        $resources = $this->provider->resources();

        $this->assertSame('audit.api.view', $resources['api-audit']['permission']);
        $this->assertSame('audit.system.view', $resources['system-audit']['permission']);
    }

    public function testApiAuditSearchSqlIncludesUserAgentHashField(): void
    {
        $resources = $this->provider->resources();
        $apiAudit = $resources['api-audit'];

        $this->assertStringContainsString('user_agent like ?', $apiAudit['count_sql']);
        $this->assertStringContainsString('user_agent like ?', $apiAudit['preview_sql']);
        $this->assertStringContainsString('user_agent like ?', $apiAudit['result_sql']);
    }

    public function testMapApiAuditItem(): void
    {
        $row = [
            'id' => 42,
            'method' => 'POST',
            'path' => '/api/v1/users',
            'status_code' => 201,
            'request_id' => 'req-abc',
            'created_at' => '2026-03-15 10:30:00',
        ];

        $result = $this->provider->mapResultItem('api-audit', $row);

        $this->assertNotNull($result);
        $this->assertSame('POST /api/v1/users', $result['title']);
        $this->assertStringContains('201', $result['subtitle']);
        $this->assertStringContains('2026-03-15 10:30:00', $result['subtitle']);
        $this->assertSame('bi-shield-check', $result['icon']);
        $this->assertStringContainsString('admin/api-audit/view/42', $result['url']);
    }

    public function testMapApiAuditItemFallsBackToRequestId(): void
    {
        $row = ['id' => 1, 'method' => '', 'path' => '', 'status_code' => 0, 'request_id' => 'req-fallback'];

        $result = $this->provider->mapResultItem('api-audit', $row);

        $this->assertNotNull($result);
        $this->assertSame('req-fallback', $result['title']);
    }

    public function testMapApiAuditItemReturnsNullWhenEmpty(): void
    {
        $row = ['id' => 1, 'method' => '', 'path' => '', 'status_code' => 0, 'request_id' => ''];

        $result = $this->provider->mapResultItem('api-audit', $row);

        $this->assertNull($result);
    }

    public function testMapSystemAuditItem(): void
    {
        $row = [
            'id' => 99,
            'event_type' => 'admin.settings.update',
            'outcome' => 'success',
            'request_id' => 'req-xyz',
            'created_at' => '2026-03-15 11:00:00',
        ];

        $result = $this->provider->mapResultItem('system-audit', $row);

        $this->assertNotNull($result);
        $this->assertSame('admin.settings.update', $result['title']);
        $this->assertStringContains('SUCCESS', $result['subtitle']);
        $this->assertStringContains('2026-03-15 11:00:00', $result['subtitle']);
        $this->assertSame('bi-journal-lock', $result['icon']);
        $this->assertStringContainsString('admin/system-audit/view/99', $result['url']);
    }

    public function testMapSystemAuditItemFallsBackToRequestId(): void
    {
        $row = ['id' => 1, 'event_type' => '', 'outcome' => '', 'request_id' => 'req-fallback'];

        $result = $this->provider->mapResultItem('system-audit', $row);

        $this->assertNotNull($result);
        $this->assertSame('req-fallback', $result['title']);
    }

    public function testMapSystemAuditItemReturnsNullWhenEmpty(): void
    {
        $row = ['id' => 1, 'event_type' => '', 'outcome' => '', 'request_id' => ''];

        $result = $this->provider->mapResultItem('system-audit', $row);

        $this->assertNull($result);
    }

    public function testMapResultItemReturnsNullForUnknownKey(): void
    {
        $result = $this->provider->mapResultItem('unknown', ['id' => 1]);

        $this->assertNull($result);
    }

    public function testListUrlForApiAudit(): void
    {
        $url = $this->provider->listUrl('api-audit', 'test%20query');

        $this->assertStringContainsString('admin/api-audit', $url);
        $this->assertStringContainsString('search=test%20query', $url);
    }

    public function testListUrlForSystemAudit(): void
    {
        $url = $this->provider->listUrl('system-audit', 'test');

        $this->assertStringContainsString('admin/system-audit', $url);
        $this->assertStringContainsString('search=test', $url);
    }

    public function testListUrlReturnsEmptyForUnknownKey(): void
    {
        $url = $this->provider->listUrl('unknown', 'test');

        $this->assertSame('', $url);
    }

    /**
     * Helper to check string containment (mirrors assertStringContainsString for readability).
     */
    private static function assertStringContains(string $needle, string $haystack): void
    {
        self::assertStringContainsString($needle, $haystack);
    }
}
