<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\File;
use Tests\TestCase;

class LogViewerTest extends TestCase
{
    use RefreshDatabase;

    protected string $testLogDir;

    protected function setUp(): void
    {
        parent::setUp();
        $this->testLogDir = storage_path('logs');
    }

    public function test_guest_is_redirected_to_login(): void
    {
        $response = $this->get(route('logs.index'));
        $response->assertRedirect(route('login'));
    }

    public function test_authenticated_user_can_view_logs(): void
    {
        $user = User::factory()->create();

        // Create a temporary log file for testing
        $tempLogName = 'test-run-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;

        $logContent = implode("\n", [
            '[2026-09-29 10:00:00] local.INFO: App booted successfully []',
            '[2026-09-29 10:05:00] local.WARNING: Slow query detected {"duration": 120}',
            '[2026-09-29 10:10:00] local.ERROR: Database connection failed {"host": "127.0.0.1"}',
            '[stacktrace]',
            '#0 /app/Database.php(42): connect()',
            '#1 /app/index.php(10): handle()',
            'CRITICAL - 2026-09-29 10:15:00 --> Out of memory error',
            'in /app/Memory.php on line 50',
            ' 1 [internal function]: shutdown()',
        ]);

        File::put($tempLogPath, $logContent);

        try {
            $response = $this->actingAs($user)->get(route('logs.index', ['file' => $tempLogName]));

            $response->assertOk();
            $response->assertSee('Error Logs');
            $response->assertSee($tempLogName);
            $response->assertSee('Database connection failed');
            $response->assertSee('Out of memory error');
            $response->assertSee('CRITICAL');
            $response->assertSee('ERROR');
            $response->assertSee('stack trace');
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_log_viewer_filters_by_level(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-level-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;

        $logContent = implode("\n", [
            '[2026-09-29 10:00:00] local.INFO: Everything normal',
            '[2026-09-29 10:05:00] local.WARNING: Memory getting high',
            '[2026-09-29 10:10:00] local.ERROR: Server crashed unexpectedly',
        ]);

        File::put($tempLogPath, $logContent);

        try {
            // Filter by ERROR
            $response = $this->actingAs($user)->get(route('logs.index', [
                'file' => $tempLogName,
                'level' => 'ERROR',
            ]));

            $response->assertOk();
            $response->assertSee('Server crashed unexpectedly');
            $response->assertDontSee('Everything normal');
            $response->assertDontSee('Memory getting high');
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_log_viewer_search_filter(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-search-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;

        $logContent = implode("\n", [
            '[2026-09-29 10:00:00] local.ERROR: Payment gateway timeout',
            '[2026-09-29 10:05:00] local.ERROR: User auth token expired',
        ]);

        File::put($tempLogPath, $logContent);

        try {
            $response = $this->actingAs($user)->get(route('logs.index', [
                'file' => $tempLogName,
                'search' => 'Payment gateway',
            ]));

            $response->assertOk();
            $response->assertSee('Payment gateway timeout');
            $response->assertDontSee('User auth token expired');
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_log_file_download(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-download-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;
        $content = "Sample log file download content\nLine 2";

        File::put($tempLogPath, $content);

        try {
            $response = $this->actingAs($user)->get(route('logs.download', ['file' => $tempLogName]));

            $response->assertOk();
            $response->assertHeader('content-disposition', 'attachment; filename='.$tempLogName);
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_download_prevents_directory_traversal(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->get(route('logs.download', ['file' => '../../.env']));
        $response->assertRedirect(route('logs.index'));
        $response->assertSessionHas('error');
    }

    public function test_clear_logs_action(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-clear-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;
        File::put($tempLogPath, "Some content that should be cleared\n");

        try {
            $response = $this->actingAs($user)->post(route('logs.clear'), [
                'action' => 'clear_current',
                'file' => $tempLogName,
            ]);

            $response->assertRedirect();
            $this->assertFileExists($tempLogPath);
            $this->assertSame(0, filesize($tempLogPath));
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_tail_filter_limits_entries(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-tail-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;

        $lines = [];
        for ($i = 1; $i <= 100; $i++) {
            $lines[] = '[2026-09-29 10:00:'.sprintf('%02d', $i % 60)."] local.INFO: Entry number {$i}";
        }
        File::put($tempLogPath, implode("\n", $lines));

        try {
            $response = $this->actingAs($user)->get(route('logs.index', [
                'file' => $tempLogName,
                'tail' => '50',
            ]));

            $response->assertOk();
            $response->assertSee('50 entries shown');
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_delete_current_file_action(): void
    {
        $user = User::factory()->create();

        $tempLogName = 'test-delete-'.time().'.log';
        $tempLogPath = $this->testLogDir.'/'.$tempLogName;
        File::put($tempLogPath, "Content to delete\n");

        try {
            $response = $this->actingAs($user)->post(route('logs.clear'), [
                'action' => 'delete_current',
                'file' => $tempLogName,
            ]);

            $response->assertRedirect();
            $this->assertFileDoesNotExist($tempLogPath);
        } finally {
            if (File::exists($tempLogPath)) {
                File::delete($tempLogPath);
            }
        }
    }

    public function test_invalid_clear_action_fails_validation(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->post(route('logs.clear'), [
            'action' => 'invalid_action',
        ]);

        $response->assertSessionHasErrors('action');
    }

    public function test_non_existent_file_redirects_gracefully(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->get(route('logs.index', ['file' => 'does-not-exist.log']));

        // Should redirect to default log file with a warning flash message
        $response->assertRedirect();
        $response->assertSessionHas('warning');
    }

    public function test_download_without_file_parameter_redirects(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->get(route('logs.download'));
        $response->assertRedirect(route('logs.index'));
        $response->assertSessionHas('error');
    }

    public function test_standard_logs_url_returns_404_not_found(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->get('/logs');
        $response->assertNotFound();
    }

    public function test_uncommon_route_uses_configured_prefix(): void
    {
        $this->assertStringContainsString('errorLogs', route('logs.index'));
    }
}
