<?php

use App\Enums\ReportReason;
use App\Enums\UserRole;
use App\Models\MealPosts;
use App\Models\ModerationCase;
use App\Models\PostReviews;
use App\Models\Report;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;

uses(RefreshDatabase::class);

it('creates a report and a moderation case for a meal post', function () {
    $reporter = User::factory()->create();
    $mealPost = MealPosts::factory()->create();

    Sanctum::actingAs($reporter);

    $this->postJson("/api/meal-posts/{$mealPost->id}/reports", [
        'reason' => ReportReason::SPAM->value,
        'details' => 'Même image publiée en boucle.',
    ])
        ->assertCreated()
        ->assertJsonPath('message', __('api.reports.created'))
        ->assertJsonPath('data.reason', ReportReason::SPAM->value)
        ->assertJsonPath('data.reportableType', 'meal_post')
        ->assertJsonPath('data.reportableId', $mealPost->id);

    $this->assertDatabaseHas('reports', [
        'reporter_id' => $reporter->id,
        'reportable_type' => MealPosts::class,
        'reportable_id' => $mealPost->id,
        'reason' => ReportReason::SPAM->value,
        'details' => 'Même image publiée en boucle.',
    ]);

    $this->assertDatabaseHas('moderation_cases', [
        'caseable_type' => MealPosts::class,
        'caseable_id' => $mealPost->id,
        'reports_count' => 1,
        'threshold' => 3,
    ]);
});

it('prevents duplicate reports and reports on own content', function () {
    $owner = User::factory()->create();
    $mealPost = MealPosts::factory()->for($owner, 'user')->create();
    $reporter = User::factory()->create();

    Sanctum::actingAs($reporter);

    $payload = ['reason' => ReportReason::OTHER->value];

    $this->postJson("/api/meal-posts/{$mealPost->id}/reports", $payload)
        ->assertCreated();

    $this->postJson("/api/meal-posts/{$mealPost->id}/reports", $payload)
        ->assertConflict()
        ->assertJsonPath('message', __('api.reports.already_exists'));

    expect(Report::query()->count())->toBe(1);

    Sanctum::actingAs($owner);

    $this->postJson("/api/meal-posts/{$mealPost->id}/reports", $payload)
        ->assertUnprocessable()
        ->assertJsonPath('message', __('api.reports.cannot_report_own_meal'));
});

it('reports users and prevents reporting own profile', function () {
    $target = User::factory()->create();
    $reporter = User::factory()->create();

    Sanctum::actingAs($reporter);

    $this->postJson("/api/users/{$target->id}/reports", [
        'reason' => ReportReason::HARASSMENT->value,
    ])
        ->assertCreated()
        ->assertJsonPath('data.reportableType', 'user')
        ->assertJsonPath('data.reportableId', $target->id);

    $this->assertDatabaseHas('moderation_cases', [
        'caseable_type' => User::class,
        'caseable_id' => $target->id,
        'threshold' => 5,
    ]);

    Sanctum::actingAs($target);

    $this->postJson("/api/users/{$target->id}/reports", [
        'reason' => ReportReason::OTHER->value,
    ])
        ->assertUnprocessable()
        ->assertJsonPath('message', __('api.reports.cannot_report_self'));
});

it('reports post reviews and prevents reporting own review', function () {
    $reviewAuthor = User::factory()->create();
    $reporter = User::factory()->create();
    $review = PostReviews::query()->create([
        'meal_post_id' => MealPosts::factory()->create()->id,
        'user_id' => $reviewAuthor->id,
        'rating' => 2,
        'comment' => 'Commentaire problématique.',
    ]);

    Sanctum::actingAs($reporter);

    $this->postJson("/api/post-reviews/{$review->id}/reports", [
        'reason' => ReportReason::INAPPROPRIATE->value,
    ])
        ->assertCreated()
        ->assertJsonPath('data.reportableType', 'post_review')
        ->assertJsonPath('data.reportableId', $review->id);

    $this->assertDatabaseHas('moderation_cases', [
        'caseable_type' => PostReviews::class,
        'caseable_id' => $review->id,
        'threshold' => 3,
    ]);

    Sanctum::actingAs($reviewAuthor);

    $this->postJson("/api/post-reviews/{$review->id}/reports", [
        'reason' => ReportReason::OTHER->value,
    ])
        ->assertUnprocessable()
        ->assertJsonPath('message', __('api.reports.cannot_report_own_review'));
});

it('notifies moderators once when a report threshold is reached', function () {
    $admin = User::factory()->create(['role' => UserRole::ADMIN]);
    $moderator = User::factory()->create(['role' => UserRole::MODERATOR]);
    $regularUser = User::factory()->create();
    $mealPost = MealPosts::factory()->create();

    foreach (User::factory()->count(3)->create() as $reporter) {
        Sanctum::actingAs($reporter);

        $this->postJson("/api/meal-posts/{$mealPost->id}/reports", [
            'reason' => ReportReason::INAPPROPRIATE->value,
        ])->assertCreated();
    }

    $moderationCase = ModerationCase::query()->where('caseable_id', $mealPost->id)->firstOrFail();

    expect($moderationCase->reports_count)->toBe(3)
        ->and($moderationCase->threshold_notified_at)->not->toBeNull();

    expect($admin->notifications)->toHaveCount(1)
        ->and($admin->notifications->first()->data['format'])->toBe('filament')
        ->and($admin->notifications->first()->data['title'])->toBe(__('api.notifications.moderation_threshold_title'))
        ->and($moderator->notifications)->toHaveCount(1)
        ->and($moderator->notifications->first()->data['format'])->toBe('filament')
        ->and($regularUser->notifications)->toHaveCount(0);

    Sanctum::actingAs(User::factory()->create());

    $this->postJson("/api/meal-posts/{$mealPost->id}/reports", [
        'reason' => ReportReason::MISLEADING->value,
    ])->assertCreated();

    expect($admin->fresh()->notifications)->toHaveCount(1)
        ->and($moderator->fresh()->notifications)->toHaveCount(1);
});
