<?php

declare(strict_types=1);

namespace Tests\Feature\Moderation;

use App\Models\User;
use App\Services\Traffic\OnlineVisitorRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;

final class OnlineVisitorsModerationTest extends TestCase
{
    use RefreshDatabase;

    protected function tearDown(): void
    {
        Mockery::close();

        parent::tearDown();
    }

    public function test_moderation_online_page_requires_staff_access(): void
    {
        $user = User::factory()->create(['role' => 'user']);

        $this->get('/moderation/traffic/online')
            ->assertRedirect(route('login'));

        $this->actingAs($user)
            ->get('/moderation/traffic/online')
            ->assertRedirect(route('index'));

        $this->actingAs($user)
            ->getJson('/moderation/traffic/online/data')
            ->assertForbidden();
    }

    public function test_staff_can_open_online_page_and_json_endpoint(): void
    {
        $admin = User::factory()->create(['role' => 'admin']);
        $repository = Mockery::mock(OnlineVisitorRepository::class);
        $repository->shouldReceive('summary')->twice()->andReturn([
            'total' => 3,
            'logged' => 1,
            'guests' => 1,
            'bots' => 1,
            'search_bots' => 1,
            'ai_bots' => 0,
            'social_bots' => 0,
            'seo_bots' => 0,
            'suspicious_bots' => 0,
        ]);
        $repository->shouldReceive('all')->twice()->andReturn([
            [
                'visitor_key' => 'user:1',
                'type' => 'human_logged',
                'user_name' => 'Gregor',
                'ip_masked' => '188.230.xxx.xxx',
                'browser' => 'Chrome',
                'platform' => 'Windows',
                'current_url' => '/wallpapers',
                'route_name' => 'wallpapers.index',
                'referer' => null,
                'first_seen_at' => now()->subMinute()->toIso8601String(),
                'last_seen_at' => now()->toIso8601String(),
                'hits' => 2,
            ],
        ]);
        $repository->shouldReceive('activePages')->twice()->andReturn([
            ['url' => '/wallpapers', 'visitors' => 3],
        ]);
        $repository->shouldReceive('track')->andReturnNull();
        $this->app->instance(OnlineVisitorRepository::class, $repository);

        $this->actingAs($admin)
            ->get('/moderation/traffic/online')
            ->assertOk()
            ->assertSee('Online Visitors')
            ->assertSee('Live view of logged users, guests, crawlers, AI bots, and suspicious traffic.');

        $this->actingAs($admin)
            ->getJson('/moderation/traffic/online/data')
            ->assertOk()
            ->assertJsonStructure([
                'summary' => ['total', 'logged', 'guests', 'bots', 'search_bots', 'ai_bots', 'social_bots', 'seo_bots', 'suspicious_bots'],
                'visitors',
                'active_pages',
                'generated_at',
            ])
            ->assertJsonPath('summary.total', 3)
            ->assertJsonPath('active_pages.0.url', '/wallpapers');
    }

    public function test_redis_failure_does_not_break_public_request(): void
    {
        $repository = Mockery::mock(OnlineVisitorRepository::class);
        $repository->shouldReceive('track')->andThrow(new \RuntimeException('Redis unavailable'));
        $this->app->instance(OnlineVisitorRepository::class, $repository);

        $this->get('/robots.txt')
            ->assertOk();
    }
}