<?php

declare(strict_types=1);

use App\Models\Order;
use App\Models\OrderRiskAssessment;
use App\Models\User;
use App\Services\FraudDetectionService;
use Database\Seeders\RoleAndPermissionSeeder;

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

// --- FraudDetectionService Tests ---

it('detects disposable email domains', function (): void {
    $service = app(FraudDetectionService::class);

    $result = $service->checkDisposableEmail('user@mailinator.com');

    expect($result['score'])->toBe(100);
    expect($result['details'])->toContain('Disposable email domain');
});

it('passes legitimate email domains', function (): void {
    $service = app(FraudDetectionService::class);

    $result = $service->checkDisposableEmail('user@gmail.com');

    expect($result['score'])->toBe(0);
    expect($result['details'])->toContain('legitimate');
});

it('flags users with previous fraud assessments', function (): void {
    $service = app(FraudDetectionService::class);
    $user = User::factory()->create();

    // Create previous high-risk assessments
    OrderRiskAssessment::factory()->count(3)->create([
        'user_id' => $user->id,
        'risk_level' => 'high',
    ]);

    $result = $service->checkPreviousFraudFlags($user);

    expect($result['score'])->toBe(100);
    expect($result['details'])->toContain('3 previous high/critical');
});

it('passes users with no previous fraud flags', function (): void {
    $service = app(FraudDetectionService::class);
    $user = User::factory()->create();

    $result = $service->checkPreviousFraudFlags($user);

    expect($result['score'])->toBe(0);
    expect($result['details'])->toContain('No previous fraud flags');
});

it('creates assessment with correct risk level based on score', function (): void {
    config(['fraud.enabled' => true]);

    $service = app(FraudDetectionService::class);
    $user = User::factory()->create(['email' => 'user@mailinator.com']);

    $assessment = $service->assess($user);

    expect($assessment)->toBeInstanceOf(OrderRiskAssessment::class);
    expect($assessment->user_id)->toBe($user->id);
    expect($assessment->risk_score)->toBeGreaterThan(0);
    expect($assessment->checks)->toBeArray();
    expect($assessment->checks)->toHaveKey('disposable_email');
    expect($assessment->checks['disposable_email']['score'])->toBe(100);
});

it('returns low risk for clean users when fraud detection is enabled', function (): void {
    config(['fraud.enabled' => true]);

    $service = app(FraudDetectionService::class);
    $user = User::factory()->create(['email' => 'clean.user@gmail.com']);

    $assessment = $service->assess($user);

    expect($assessment->risk_score)->toBeLessThanOrEqual(30);
    expect($assessment->auto_action)->toBe('approve');
});

it('bypasses checks when fraud detection is disabled', function (): void {
    config(['fraud.enabled' => false]);

    $service = app(FraudDetectionService::class);
    $user = User::factory()->create(['email' => 'user@mailinator.com']);

    $assessment = $service->assess($user);

    expect($assessment->risk_score)->toBe(0);
    expect($assessment->auto_action)->toBe('approve');
    expect($assessment->risk_level)->toBe('low');
});

it('associates assessment with order when provided', function (): void {
    config(['fraud.enabled' => true]);

    $service = app(FraudDetectionService::class);
    $user = User::factory()->create();
    $order = Order::factory()->create(['user_id' => $user->id]);

    $assessment = $service->assess($user, $order);

    expect($assessment->order_id)->toBe($order->id);
});

it('applies correct thresholds from config', function (): void {
    config([
        'fraud.enabled' => true,
        'fraud.thresholds.auto_approve_below' => 30,
        'fraud.thresholds.auto_hold_above' => 60,
        'fraud.thresholds.auto_reject_above' => 85,
    ]);

    $service = app(FraudDetectionService::class);

    // User with disposable email should score high
    $user = User::factory()->create(['email' => 'test@mailinator.com']);
    $assessment = $service->assess($user);

    // disposable_email check returns 100, weight is 25 => 25 weighted score minimum
    expect($assessment->risk_score)->toBeGreaterThanOrEqual(25);
});

// --- Admin Fraud Queue Tests ---

it('admin can view fraud queue', function (): void {
    $admin = User::factory()->admin()->create();
    OrderRiskAssessment::factory()->count(3)->create();

    $this->actingAs($admin)
        ->get($this->adminUrl.'/fraud-queue')
        ->assertOk()
        ->assertInertia(fn ($page) => $page
            ->component('Admin/FraudQueue/Index')
            ->has('assessments')
        );
});

it('admin can view fraud assessment detail', function (): void {
    $admin = User::factory()->admin()->create();
    $assessment = OrderRiskAssessment::factory()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl."/fraud-queue/{$assessment->id}")
        ->assertOk()
        ->assertInertia(fn ($page) => $page
            ->component('Admin/FraudQueue/Show')
            ->has('assessment')
        );
});

it('admin can approve fraud assessment', function (): void {
    $admin = User::factory()->admin()->create();
    $order = Order::factory()->pending()->create();
    $assessment = OrderRiskAssessment::factory()->high()->create([
        'order_id' => $order->id,
        'user_id' => $order->user_id,
    ]);

    $this->actingAs($admin)
        ->post($this->adminUrl."/fraud-queue/{$assessment->id}/approve")
        ->assertRedirect();

    $assessment->refresh();
    expect($assessment->reviewed_by)->toBe($admin->id);
    expect($assessment->reviewed_at)->not->toBeNull();
    expect($assessment->auto_action)->toBe('approve');

    $order->refresh();
    expect($order->status)->toBe('processing');
});

it('admin can reject fraud assessment and cancel order', function (): void {
    $admin = User::factory()->admin()->create();
    $order = Order::factory()->pending()->create();
    $assessment = OrderRiskAssessment::factory()->critical()->create([
        'order_id' => $order->id,
        'user_id' => $order->user_id,
    ]);

    $this->actingAs($admin)
        ->post($this->adminUrl."/fraud-queue/{$assessment->id}/reject")
        ->assertRedirect();

    $assessment->refresh();
    expect($assessment->reviewed_by)->toBe($admin->id);
    expect($assessment->auto_action)->toBe('reject');

    $order->refresh();
    expect($order->status)->toBe('cancelled');
    expect($order->cancelled_at)->not->toBeNull();
});

it('fraud queue filters by risk level', function (): void {
    $admin = User::factory()->admin()->create();
    OrderRiskAssessment::factory()->high()->create();
    OrderRiskAssessment::factory()->low()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl.'/fraud-queue?risk_level=high')
        ->assertOk()
        ->assertInertia(fn ($page) => $page
            ->component('Admin/FraudQueue/Index')
            ->has('assessments.data', 1)
        );
});
