<?php

namespace Tests\Feature\Http\Controllers\Api\V1;

use App\Enums\LogLevelEnum;
use App\Models\Log;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LogsControllerTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        // Clear any logs that may have been created during application startup
        Log::query()->delete();
    }

    public function test_index_returns_successful_response(): void
    {
        Log::factory()->count(5)->create();

        $response = $this->getJson('/api/v1/logs');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [
                    'logs' => [
                        '*' => [
                            'id',
                            'level',
                            'message',
                            'context',
                            'created_at',
                            'updated_at',
                        ],
                    ],
                    'pagination' => [
                        'current_page',
                        'last_page',
                        'per_page',
                        'total',
                        'from',
                        'to',
                    ],
                ],
            ])
            ->assertJson([
                'success' => true,
                'message' => 'Logs retrieved successfully.',
            ]);
    }

    public function test_index_orders_logs_by_created_at_desc(): void
    {
        $oldLog = Log::factory()->create(['created_at' => now()->subDays(2)]);
        $newLog = Log::factory()->create(['created_at' => now()->subDay()]);
        $newestLog = Log::factory()->create(['created_at' => now()]);

        $response = $this->getJson('/api/v1/logs');

        $response->assertStatus(200);

        $logs = $response->json('data.logs');

        $this->assertEquals($newestLog->id, $logs[0]['id']);
        $this->assertEquals($newLog->id, $logs[1]['id']);
        $this->assertEquals($oldLog->id, $logs[2]['id']);
    }

    public function test_index_filters_by_level(): void
    {
        Log::factory()->create(['level' => LogLevelEnum::ERROR]);
        Log::factory()->create(['level' => LogLevelEnum::WARNING]);
        Log::factory()->create(['level' => LogLevelEnum::INFO]);

        $response = $this->getJson('/api/v1/logs?level=error');

        $response->assertStatus(200);

        $logs = $response->json('data.logs');

        $this->assertCount(1, $logs);
        $this->assertEquals('error', $logs[0]['level']);
    }

    public function test_index_respects_per_page_parameter(): void
    {
        Log::factory()->count(15)->create();

        $response = $this->getJson('/api/v1/logs?per_page=5');

        $response->assertStatus(200);

        $logs = $response->json('data.logs');
        $pagination = $response->json('data.pagination');

        $this->assertCount(5, $logs);
        $this->assertEquals(5, $pagination['per_page']);
        $this->assertEquals(15, $pagination['total']);
        $this->assertEquals(3, $pagination['last_page']);
    }

    public function test_index_limits_per_page_to_maximum(): void
    {
        Log::factory()->count(10)->create();

        $response = $this->getJson('/api/v1/logs?per_page=150');

        $response->assertStatus(200);

        $pagination = $response->json('data.pagination');

        // Should be limited to 100 as per controller logic
        $this->assertEquals(100, $pagination['per_page']);
    }

    public function test_index_uses_default_per_page_when_not_specified(): void
    {
        Log::factory()->count(25)->create();

        $response = $this->getJson('/api/v1/logs');

        $response->assertStatus(200);

        $pagination = $response->json('data.pagination');

        // Should use default of 20
        $this->assertEquals(20, $pagination['per_page']);
    }

    public function test_index_handles_empty_logs(): void
    {
        $response = $this->getJson('/api/v1/logs');

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'message' => 'Logs retrieved successfully.',
                'data' => [
                    'logs' => [],
                    'pagination' => [
                        'total' => 0,
                        'current_page' => 1,
                        'last_page' => 1,
                    ],
                ],
            ]);
    }

    public function test_index_pagination_works_correctly(): void
    {
        Log::factory()->count(25)->create();

        // Test first page
        $response = $this->getJson('/api/v1/logs?per_page=10&page=1');
        $response->assertStatus(200);

        $pagination = $response->json('data.pagination');
        $this->assertEquals(1, $pagination['current_page']);
        $this->assertEquals(3, $pagination['last_page']);
        $this->assertEquals(1, $pagination['from']);
        $this->assertEquals(10, $pagination['to']);

        // Test second page
        $response = $this->getJson('/api/v1/logs?per_page=10&page=2');
        $response->assertStatus(200);

        $pagination = $response->json('data.pagination');
        $this->assertEquals(2, $pagination['current_page']);
        $this->assertEquals(11, $pagination['from']);
        $this->assertEquals(20, $pagination['to']);
    }

    public function test_index_with_multiple_log_levels(): void
    {
        Log::factory()->create(['level' => LogLevelEnum::ERROR, 'message' => 'Error message']);
        Log::factory()->create(['level' => LogLevelEnum::WARNING, 'message' => 'Warning message']);
        Log::factory()->create(['level' => LogLevelEnum::INFO, 'message' => 'Info message']);
        Log::factory()->create(['level' => LogLevelEnum::DEBUG, 'message' => 'Debug message']);

        $response = $this->getJson('/api/v1/logs');

        $response->assertStatus(200);

        $logs = $response->json('data.logs');

        $this->assertCount(4, $logs);

        $levels = array_column($logs, 'level');
        $this->assertContains('error', $levels);
        $this->assertContains('warning', $levels);
        $this->assertContains('info', $levels);
        $this->assertContains('debug', $levels);
    }
}
