<?php

namespace Tests\Feature;

use App\Http\Middleware\EnsureAdminProjectAccess;
use App\Http\Middleware\LogAdminActivity;
use App\Models\Admin;
use App\Models\User;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class AdminSecurityHardeningTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->createTables();
    }

    public function test_admin_login_is_rate_limited_after_repeated_failures(): void
    {
        Admin::query()->create([
            'name' => 'Security Admin',
            'email' => 'security@example.com',
            'password' => Hash::make('CorrectPassword123'),
        ]);

        foreach (range(1, 5) as $attempt) {
            $this->from('/admin/login')->post(route('admin.login.submit'), [
                'email' => 'security@example.com',
                'password' => 'wrong-password',
            ]);
        }

        $response = $this->from('/admin/login')->post(route('admin.login.submit'), [
            'email' => 'security@example.com',
            'password' => 'CorrectPassword123',
        ]);

        $response->assertRedirect('/admin/login');
        $response->assertSessionHasErrors(['email']);
        $this->assertGuest('admin');
    }

    public function test_admin_user_impersonation_requires_current_admin_password(): void
    {
        $admin = Admin::query()->create([
            'name' => 'Security Admin',
            'email' => 'security@example.com',
            'password' => Hash::make('CorrectPassword123'),
        ]);

        $user = User::query()->create([
            'name' => 'Member User',
            'email' => 'member@example.com',
            'password' => Hash::make('user-password'),
            'mobile' => '01700000000',
        ]);

        $response = $this->withoutMiddleware([
            EnsureAdminProjectAccess::class,
            LogAdminActivity::class,
        ])->actingAs($admin, 'admin')
            ->from('/admin/users')
            ->post(route('admin.users.login', $user->id), [
                'admin_password' => 'wrong-password',
            ]);

        $response->assertRedirect('/admin/users');
        $response->assertSessionHas('error');
        $this->assertAuthenticatedAs($admin, 'admin');
        $this->assertGuest('web');
    }

    public function test_admin_user_update_accepts_configured_security_password(): void
    {
        Config::set('admin_security.edit_password', 'EditSecret123');

        $admin = Admin::query()->create([
            'name' => 'Security Admin',
            'email' => 'security@example.com',
            'password' => Hash::make('CorrectPassword123'),
        ]);

        $user = User::query()->create([
            'name' => 'Member User',
            'email' => 'member@example.com',
            'password' => Hash::make('user-password'),
            'mobile' => '01700000000',
        ]);

        $response = $this->withoutMiddleware([
            EnsureAdminProjectAccess::class,
            LogAdminActivity::class,
        ])->actingAs($admin, 'admin')
            ->from('/admin/users/' . $user->id . '/edit')
            ->post(route('admin.users.update', $user->id), [
                'name' => 'Updated Member',
                'email' => 'member@example.com',
                'mobile' => '01700000000',
                'admin_password' => 'EditSecret123',
            ]);

        $response->assertRedirect(route('admin.users'));
        $response->assertSessionHas('success');
        $this->assertSame('Updated Member', $user->fresh()->name);
    }

    public function test_admin_user_impersonation_accepts_configured_security_password(): void
    {
        Config::set('admin_security.impersonate_key', 'ImpersonateSecret123');

        $admin = Admin::query()->create([
            'name' => 'Security Admin',
            'email' => 'security@example.com',
            'password' => Hash::make('CorrectPassword123'),
        ]);

        $user = User::query()->create([
            'name' => 'Member User',
            'email' => 'member@example.com',
            'password' => Hash::make('user-password'),
            'mobile' => '01700000000',
        ]);

        $response = $this->withoutMiddleware([
            EnsureAdminProjectAccess::class,
            LogAdminActivity::class,
        ])->actingAs($admin, 'admin')
            ->post(route('admin.users.login', $user->id), [
                'admin_password' => 'ImpersonateSecret123',
            ]);

        $response->assertRedirect(route('dashboard'));
        $this->assertGuest('admin');
        $this->assertAuthenticatedAs($user, 'web');
    }

    protected function tearDown(): void
    {
        RateLimiter::clear('admin-login:security@example.com|127.0.0.1');
        parent::tearDown();
    }

    private function createTables(): void
    {
        Schema::dropIfExists('users');
        Schema::dropIfExists('admins');

        Schema::create('admins', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->string('mobile')->nullable();
            $table->rememberToken();
            $table->timestamps();
        });
    }
}
