<?php

declare(strict_types=1);

use App\Models\AuditLog;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;

beforeEach(function (): void {
    $this->seed(RoleAndPermissionSeeder::class);
    $this->adminUrl = 'http://'.config('app.domains.admin');
});

describe('Audit Log Export', function (): void {
    it('exports audit logs as CSV', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create(['name' => 'Test Customer']);

        AuditLog::factory()->count(3)->create([
            'user_id' => $customer->id,
            'action' => 'login',
            'changes' => ['before' => ['status' => 'inactive'], 'after' => ['status' => 'active']],
        ]);

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=csv');

        $response->assertOk();
        $response->assertHeader('content-type', 'text/csv; charset=UTF-8');
        $response->assertDownload();
    });

    it('includes all required fields in CSV export', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create(['name' => 'Test Customer', 'email' => 'test@example.com']);

        AuditLog::factory()->create([
            'user_id' => $customer->id,
            'action' => 'update_profile',
            'resource_type' => 'user',
            'resource_id' => $customer->id,
            'ip_address' => '192.168.1.1',
            'user_agent' => 'Mozilla/5.0',
            'changes' => ['before' => ['name' => 'Old Name'], 'after' => ['name' => 'New Name']],
        ]);

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=csv');

        $response->assertOk();

        $csv = $response->streamedContent();
        $lines = explode("\n", $csv);

        // Check header row
        expect($lines[0])->toContain('ID')
            ->and($lines[0])->toContain('Date')
            ->and($lines[0])->toContain('User')
            ->and($lines[0])->toContain('User Email')
            ->and($lines[0])->toContain('Action')
            ->and($lines[0])->toContain('Resource Type')
            ->and($lines[0])->toContain('Resource ID')
            ->and($lines[0])->toContain('IP Address')
            ->and($lines[0])->toContain('User Agent')
            ->and($lines[0])->toContain('Changes Summary');

        // Check data row
        expect($lines[1])->toContain('Test Customer')
            ->and($lines[1])->toContain('test@example.com')
            ->and($lines[1])->toContain('update_profile')
            ->and($lines[1])->toContain('user')
            ->and($lines[1])->toContain('192.168.1.1')
            ->and($lines[1])->toContain('Mozilla/5.0');
    });

    it('exports audit logs as JSON', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create(['name' => 'Test Customer']);

        AuditLog::factory()->count(3)->create([
            'user_id' => $customer->id,
            'action' => 'update_plan',
            'resource_type' => 'plan',
            'resource_id' => 1,
            'changes' => ['before' => ['name' => 'Basic'], 'after' => ['name' => 'Pro']],
        ]);

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=json');

        $response->assertOk();
        $response->assertHeader('content-type', 'application/json');
        $response->assertDownload();
    });

    it('applies search filter to CSV export', function (): void {
        $admin = User::factory()->admin()->create();
        $customer = User::factory()->customer()->create(['name' => 'Alice']);

        AuditLog::factory()->create([
            'user_id' => $customer->id,
            'action' => 'login',
        ]);

        AuditLog::factory()->create([
            'user_id' => $admin->id,
            'action' => 'create_plan',
        ]);

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=csv&action=login');

        $response->assertOk();
        $response->assertDownload();
    });

    it('applies date range filter to export', function (): void {
        $admin = User::factory()->admin()->create();

        AuditLog::factory()->create([
            'user_id' => $admin->id,
            'action' => 'login',
            'created_at' => now()->subDays(5),
        ]);

        AuditLog::factory()->create([
            'user_id' => $admin->id,
            'action' => 'update_settings',
            'created_at' => now(),
        ]);

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=csv&date_from='.now()->subDays(2)->format('Y-m-d').'&date_to='.now()->format('Y-m-d'));

        $response->assertOk();
        $response->assertDownload();
    });

    it('requires format parameter for export', function (): void {
        $admin = User::factory()->admin()->create();

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export');

        $response->assertInvalid(['format']);
    });

    it('rejects invalid format parameter', function (): void {
        $admin = User::factory()->admin()->create();

        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=xml');

        $response->assertInvalid(['format']);
    });

    it('denies customer access to audit log export', function (): void {
        $customer = User::factory()->customer()->create();

        $this->actingAs($customer)
            ->get($this->adminUrl.'/audit-logs/export?format=csv')
            ->assertForbidden();
    });

    it('redirects guest when exporting audit logs', function (): void {
        $this->get($this->adminUrl.'/audit-logs/export?format=csv')
            ->assertRedirect();
    });

    it('applies all filters simultaneously to CSV export', function (): void {
        $admin = User::factory()->admin()->create();
        $alice = User::factory()->customer()->create(['name' => 'Alice', 'email' => 'alice@example.com']);
        $bob = User::factory()->customer()->create(['name' => 'Bob', 'email' => 'bob@example.com']);

        // Create logs with different actions and dates
        AuditLog::factory()->create([
            'user_id' => $alice->id,
            'action' => 'login',
            'created_at' => now()->subDays(3),
        ]);

        AuditLog::factory()->create([
            'user_id' => $alice->id,
            'action' => 'update_profile',
            'created_at' => now()->subDay(),
        ]);

        AuditLog::factory()->create([
            'user_id' => $bob->id,
            'action' => 'login',
            'created_at' => now()->subDay(),
        ]);

        // Export with multiple filters (search=alice, action=login, recent dates)
        $response = $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs/export?format=csv&search=alice&action=login&date_from='.now()->subDays(4)->format('Y-m-d').'&date_to='.now()->format('Y-m-d'));

        $response->assertOk();
        $csv = $response->streamedContent();
        $lines = array_filter(explode("\n", $csv));

        // Should only include 1 data row (Alice's login) + 1 header row
        expect(count($lines))->toBe(2);
        expect($lines[1])->toContain('Alice');
        expect($lines[1])->toContain('login');
    });
});

describe('Audit Log Index - Changes Detail', function (): void {
    it('displays audit logs with changes data', function (): void {
        $admin = User::factory()->admin()->create();

        AuditLog::factory()->create([
            'user_id' => $admin->id,
            'action' => 'update_plan',
            'resource_type' => 'plan',
            'resource_id' => 1,
            'changes' => [
                'before' => ['name' => 'Basic', 'price' => '9.99'],
                'after' => ['name' => 'Pro', 'price' => '19.99'],
            ],
        ]);

        $this->actingAs($admin)
            ->get($this->adminUrl.'/audit-logs')
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('Admin/AuditLogs/Index')
                ->has('auditLogs.data', 1)
                ->where('auditLogs.data.0.changes.before.name', 'Basic')
                ->where('auditLogs.data.0.changes.after.name', 'Pro')
            );
    });
});
