<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Livewire\Admin\Blog\PostReviews\Manage as BlogPostReviewsManage;
use App\Models\BlogPost;
use App\Models\BlogPostReview;
use App\Models\User;
use App\Services\Blog\RandomBlogPostReviewGenerator;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

final class AdminBlogRandomReviewsTest extends TestCase
{
    use RefreshDatabase;

    public function test_generator_creates_guest_reviews_with_expected_fields(): void
    {
        $post = BlogPost::factory()->create(['title' => 'Payments overview 2026']);

        $generator = new RandomBlogPostReviewGenerator;
        $n = $generator->generate($post, 4);

        $this->assertSame(4, $n);
        $this->assertSame(4, BlogPostReview::query()->where('blog_post_id', $post->id)->count());

        $review = BlogPostReview::query()->where('blog_post_id', $post->id)->first();
        $this->assertNotNull($review);
        $this->assertNull($review->user_id);
        $this->assertNotEmpty($review->guest_name);
        $this->assertGreaterThanOrEqual(1, $review->rating);
        $this->assertLessThanOrEqual(5, $review->rating);
        $this->assertNotNull($review->body);
        $this->assertGreaterThan(15, strlen((string) $review->body));
        $this->assertTrue($review->is_approved);

        $anyMentionsTitle = BlogPostReview::query()
            ->where('blog_post_id', $post->id)
            ->where('body', 'like', '%Payments overview 2026%')
            ->exists();
        $this->assertTrue($anyMentionsTitle, 'At least one generated review should reference the post title.');
    }

    public function test_generator_spreads_timestamps_within_date_range(): void
    {
        $post = BlogPost::factory()->create(['title' => 'Dated reviews']);

        $from = Carbon::parse('2003-04-11', config('app.timezone'))->startOfDay();
        $to = Carbon::parse('2026-04-04', config('app.timezone'))->endOfDay();

        $generator = new RandomBlogPostReviewGenerator;
        $generator->generate($post, 25, $from, $to);

        $reviews = BlogPostReview::query()->where('blog_post_id', $post->id)->get();
        $this->assertCount(25, $reviews);

        foreach ($reviews as $review) {
            $this->assertNotNull($review->created_at);
            $this->assertTrue(
                $review->created_at->greaterThanOrEqualTo($from) && $review->created_at->lessThanOrEqualTo($to),
                'Review created_at should fall within the chosen range.'
            );
            $this->assertTrue($review->updated_at->equalTo($review->created_at));
        }

        $uniqueMinutes = $reviews->pluck('created_at')->map(fn ($c) => $c->format('Y-m-d H:i'))->unique()->count();
        $this->assertGreaterThan(1, $uniqueMinutes, 'Random timestamps should not all be identical.');
    }

    public function test_admin_can_generate_reviews_from_review_management(): void
    {
        Role::findOrCreate('admin');
        $admin = User::factory()->create();
        $admin->assignRole('admin');

        $post = BlogPost::factory()->create(['title' => 'Stripe deep dive']);

        Livewire::actingAs($admin)
            ->test(BlogPostReviewsManage::class)
            ->set('bulkPostId', $post->id)
            ->set('bulkCount', 2)
            ->call('generateBulk')
            ->assertHasNoErrors();

        $this->assertSame(2, BlogPostReview::query()->where('blog_post_id', $post->id)->count());
    }

    public function test_guest_cannot_open_blog_posts_admin_index(): void
    {
        $this->get(route('admin.blog.posts.index'))
            ->assertRedirect();
    }
}
