<?php

use App\Models\MealPosts;
use App\Models\PostReviews;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;

uses(RefreshDatabase::class);

it('creates one review per user for a meal post', function () {
    $user = User::factory()->create();
    $mealPost = MealPosts::factory()->create();

    Sanctum::actingAs($user);

    $this->postJson("/api/meal-posts/{$mealPost->id}/reviews", [
        'rating' => 5,
        'comment' => 'Très bon repas.',
    ])
        ->assertCreated()
        ->assertJsonPath('data.rating', 5)
        ->assertJsonPath('data.comment', 'Très bon repas.')
        ->assertJsonPath('data.meal_post_id', $mealPost->id)
        ->assertJsonPath('data.user_id', $user->id);

    $this->assertDatabaseHas('post_reviews', [
        'meal_post_id' => $mealPost->id,
        'user_id' => $user->id,
        'rating' => 5,
        'comment' => 'Très bon repas.',
    ]);

    $this->postJson("/api/meal-posts/{$mealPost->id}/reviews", [
        'rating' => 4,
    ])
        ->assertConflict()
        ->assertJsonPath('message', 'Vous avez déjà donné un avis pour ce repas.');

    expect(PostReviews::query()->count())->toBe(1);
});

it('lists reviews for a single meal post', function () {
    $user = User::factory()->create();
    $mealPost = MealPosts::factory()->create();
    $otherMealPost = MealPosts::factory()->create();
    $firstReview = PostReviews::query()->create([
        'meal_post_id' => $mealPost->id,
        'user_id' => User::factory()->create()->id,
        'rating' => 4,
        'comment' => 'Solide.',
    ]);
    $secondReview = PostReviews::query()->create([
        'meal_post_id' => $mealPost->id,
        'user_id' => User::factory()->create()->id,
        'rating' => 5,
        'comment' => null,
    ]);
    $otherReview = PostReviews::query()->create([
        'meal_post_id' => $otherMealPost->id,
        'user_id' => User::factory()->create()->id,
        'rating' => 1,
        'comment' => 'Pas celui-ci.',
    ]);

    Sanctum::actingAs($user);

    $this->getJson("/api/meal-posts/{$mealPost->id}/reviews")
        ->assertOk()
        ->assertJsonCount(2, 'data')
        ->assertJsonFragment(['id' => $firstReview->id])
        ->assertJsonFragment(['id' => $secondReview->id])
        ->assertJsonMissing(['id' => $otherReview->id]);
});

it('lets the review author update and delete their review', function () {
    $user = User::factory()->create();
    $review = PostReviews::query()->create([
        'meal_post_id' => MealPosts::factory()->create()->id,
        'user_id' => $user->id,
        'rating' => 3,
        'comment' => 'Initial.',
    ]);

    Sanctum::actingAs($user);

    $this->patchJson("/api/post-reviews/{$review->id}", [
        'rating' => 4,
        'comment' => null,
    ])
        ->assertOk()
        ->assertJsonPath('data.rating', 4)
        ->assertJsonPath('data.comment', null);

    $this->assertDatabaseHas('post_reviews', [
        'id' => $review->id,
        'rating' => 4,
        'comment' => null,
    ]);

    $this->deleteJson("/api/post-reviews/{$review->id}")
        ->assertNoContent();

    $this->assertDatabaseMissing('post_reviews', [
        'id' => $review->id,
    ]);
});

it('does not let another user mutate a review', function () {
    $review = PostReviews::query()->create([
        'meal_post_id' => MealPosts::factory()->create()->id,
        'user_id' => User::factory()->create()->id,
        'rating' => 3,
        'comment' => 'Initial.',
    ]);

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

    $this->patchJson("/api/post-reviews/{$review->id}", [
        'rating' => 4,
    ])->assertNotFound();

    $this->deleteJson("/api/post-reviews/{$review->id}")
        ->assertNotFound();

    $this->assertDatabaseHas('post_reviews', [
        'id' => $review->id,
        'rating' => 3,
    ]);
});

it('requires authentication to create a review', function () {
    $mealPost = MealPosts::factory()->create();

    $this->postJson("/api/meal-posts/{$mealPost->id}/reviews", [
        'rating' => 5,
    ])->assertUnauthorized();
});
