<?php

namespace Tests\Feature;

use App\Models\User;
use App\Models\Product;
use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Hash;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class SecurityPerformanceTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    protected function setUp(): void
    {
        parent::setUp();
        
        // Create roles
        Role::create(['name' => 'admin']);
        Role::create(['name' => 'staff']);
        Role::create(['name' => 'customer']);
    }

    /** @test */
    public function test_admin_can_access_user_management()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $response = $this->actingAs($admin)->get('/admin/users');
        
        $response->assertStatus(200);
        $response->assertSee('Users Management');
    }

    /** @test */
    public function test_staff_cannot_create_new_staff()
    {
        $staff = User::factory()->create();
        $staff->assignRole('staff');

        $response = $this->actingAs($staff)->get('/admin/users/create');
        
        $response->assertStatus(403);
    }

    /** @test */
    public function test_customer_cannot_access_admin_panel()
    {
        $customer = User::factory()->create();

        $response = $this->actingAs($customer)->get('/admin/users');
        
        $response->assertStatus(403);
    }

    /** @test */
    public function test_banned_user_functionality()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');
        
        $customer = User::factory()->create();

        // Ban the customer
        $response = $this->actingAs($admin)
            ->put("/admin/users/{$customer->id}/ban");
        
        $response->assertRedirect();
        $response->assertSessionHas('success');
        
        $customer->refresh();
        $this->assertNotNull($customer->banned_at);
        $this->assertTrue($customer->isBanned());
        $this->assertFalse($customer->isActive());
    }

    /** @test */
    public function test_cannot_ban_admin_users()
    {
        $admin1 = User::factory()->create();
        $admin1->assignRole('admin');
        
        $admin2 = User::factory()->create();
        $admin2->assignRole('admin');

        $response = $this->actingAs($admin1)
            ->put("/admin/users/{$admin2->id}/ban");
        
        $response->assertRedirect();
        $response->assertSessionHas('error');
        
        $admin2->refresh();
        $this->assertNull($admin2->banned_at);
    }

    /** @test */
    public function test_cannot_ban_self()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $response = $this->actingAs($admin)
            ->put("/admin/users/{$admin->id}/ban");
        
        $response->assertRedirect();
        $response->assertSessionHas('error');
        
        $admin->refresh();
        $this->assertNull($admin->banned_at);
    }

    /** @test */
    public function test_staff_creation_validation()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        // Test with invalid data
        $response = $this->actingAs($admin)->post('/admin/users', [
            'name' => '',
            'mobile' => '',
            'password' => '123',
            'password_confirmation' => '456',
            'roles' => []
        ]);

        $response->assertSessionHasErrors(['name', 'mobile', 'password', 'roles']);
    }

    /** @test */
    public function test_staff_creation_success()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $staffData = [
            'name' => 'Test Staff',
            'mobile' => '9876543210',
            'email' => 'staff@test.com',
            'password' => 'password123',
            'password_confirmation' => 'password123',
            'roles' => ['staff']
        ];

        $response = $this->actingAs($admin)->post('/admin/users', $staffData);

        $response->assertRedirect('/admin/users?tab=staff');
        $response->assertSessionHas('success');

        $this->assertDatabaseHas('users', [
            'name' => 'Test Staff',
            'mobile' => '9876543210',
            'email' => 'staff@test.com'
        ]);

        $staff = User::where('mobile', '9876543210')->first();
        $this->assertTrue($staff->hasRole('staff'));
        $this->assertNotNull($staff->mobile_verified_at);
    }

    /** @test */
    public function test_pos_staff_api_security()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $staff = User::factory()->create();
        $staff->assignRole('staff');

        $customer = User::factory()->create();

        // Admin should access
        $response = $this->actingAs($admin)->get('/admin/api/pos/staff');
        $response->assertStatus(200);

        // Staff should access
        $response = $this->actingAs($staff)->get('/admin/api/pos/staff');
        $response->assertStatus(200);

        // Customer should not access
        $response = $this->actingAs($customer)->get('/admin/api/pos/staff');
        $response->assertStatus(403);
    }

    /** @test */
    public function test_salesman_report_access_control()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $staff = User::factory()->create();
        $staff->assignRole('staff');

        $customer = User::factory()->create();

        // Admin should access
        $response = $this->actingAs($admin)->get('/admin/reports/salesman');
        $response->assertStatus(200);

        // Staff should access
        $response = $this->actingAs($staff)->get('/admin/reports/salesman');
        $response->assertStatus(200);

        // Customer should not access
        $response = $this->actingAs($customer)->get('/admin/reports/salesman');
        $response->assertStatus(403);
    }

    /** @test */
    public function test_password_hashing()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $staffData = [
            'name' => 'Test Staff',
            'mobile' => '9876543210',
            'password' => 'plainpassword',
            'password_confirmation' => 'plainpassword',
            'roles' => ['staff']
        ];

        $this->actingAs($admin)->post('/admin/users', $staffData);

        $staff = User::where('mobile', '9876543210')->first();
        
        // Password should be hashed
        $this->assertNotEquals('plainpassword', $staff->password);
        $this->assertTrue(Hash::check('plainpassword', $staff->password));
    }

    /** @test */
    public function test_unique_mobile_validation()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $existingUser = User::factory()->create(['mobile' => '9876543210']);

        $staffData = [
            'name' => 'Test Staff',
            'mobile' => '9876543210', // Same mobile
            'password' => 'password123',
            'password_confirmation' => 'password123',
            'roles' => ['staff']
        ];

        $response = $this->actingAs($admin)->post('/admin/users', $staffData);

        $response->assertSessionHasErrors(['mobile']);
    }

    /** @test */
    public function test_csrf_protection()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $customer = User::factory()->create();

        // Try to ban without CSRF token
        $response = $this->actingAs($admin)
            ->put("/admin/users/{$customer->id}/ban", [], [
                'X-CSRF-TOKEN' => 'invalid-token'
            ]);

        $response->assertStatus(419); // CSRF token mismatch
    }

    /** @test */
    public function test_sql_injection_protection()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        // Try SQL injection in staff creation
        $maliciousData = [
            'name' => "'; DROP TABLE users; --",
            'mobile' => '9876543210',
            'password' => 'password123',
            'password_confirmation' => 'password123',
            'roles' => ['staff']
        ];

        $response = $this->actingAs($admin)->post('/admin/users', $maliciousData);

        // Should either succeed with escaped data or fail validation
        // But should not execute SQL injection
        $this->assertDatabaseMissing('users', ['name' => "'; DROP TABLE users; --"]);
        
        // Verify users table still exists
        $this->assertDatabaseHas('users', ['id' => $admin->id]);
    }

    /** @test */
    public function test_mass_assignment_protection()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        // Try to set non-fillable fields
        $maliciousData = [
            'name' => 'Test Staff',
            'mobile' => '9876543210',
            'password' => 'password123',
            'password_confirmation' => 'password123',
            'roles' => ['staff'],
            'id' => 999999, // Try to set ID
            'created_at' => '2020-01-01', // Try to set timestamp
        ];

        $response = $this->actingAs($admin)->post('/admin/users', $maliciousData);

        if ($response->isRedirect()) {
            $staff = User::where('mobile', '9876543210')->first();
            if ($staff) {
                $this->assertNotEquals(999999, $staff->id);
                $this->assertNotEquals('2020-01-01', $staff->created_at->format('Y-m-d'));
            }
        }
    }

    /** @test */
    public function test_performance_user_listing_pagination()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        // Create many users to test pagination
        User::factory()->count(50)->create();

        $startTime = microtime(true);
        
        $response = $this->actingAs($admin)->get('/admin/users');
        
        $endTime = microtime(true);
        $executionTime = $endTime - $startTime;

        $response->assertStatus(200);
        
        // Should complete within reasonable time (2 seconds)
        $this->assertLessThan(2.0, $executionTime, 'User listing took too long');
    }

    /** @test */
    public function test_performance_salesman_report()
    {
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        // Create test data
        $staff = User::factory()->create();
        $staff->assignRole('staff');

        $products = Product::factory()->count(10)->create([
            'purchase_price' => 50.00,
            'price' => 100.00
        ]);

        // Create orders with staff_id
        Order::factory()->count(20)->create([
            'staff_id' => $staff->id,
            'payment_status' => 'paid'
        ]);

        $startTime = microtime(true);
        
        $response = $this->actingAs($admin)->get('/admin/reports/salesman');
        
        $endTime = microtime(true);
        $executionTime = $endTime - $startTime;

        $response->assertStatus(200);
        
        // Should complete within reasonable time (3 seconds)
        $this->assertLessThan(3.0, $executionTime, 'Salesman report took too long');
    }
}