<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Livewire\Admin\Blog\Posts\Form as BlogPostsForm;
use App\Models\BlogCategory;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

final class AdminBlogPostCreateTest extends TestCase
{
    use RefreshDatabase;

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

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

        $this->actingAs($user)
            ->get(route('admin.blog.posts.create'))
            ->assertForbidden();
    }

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

        BlogCategory::query()->create([
            'name' => 'News',
            'slug' => 'news',
            'description' => null,
            'sort_order' => 0,
        ]);

        $url = route('admin.blog.posts.create');
        $this->assertStringEndsWith('/admin/blog/posts/create', parse_url($url, PHP_URL_PATH) ?? '');

        $this->actingAs($admin)
            ->get($url)
            ->assertOk()
            ->assertSee('Add new post', false);
    }

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

        $category = BlogCategory::query()->create([
            'name' => 'Guides',
            'slug' => 'guides',
            'description' => null,
            'sort_order' => 0,
        ]);

        Livewire::actingAs($admin)
            ->test(BlogPostsForm::class)
            ->set('title', 'First admin post')
            ->set('content', '<p>'.str_repeat('a', 25).'</p>')
            ->set('status', 'draft')
            ->set('blog_category_id', $category->id)
            ->call('save')
            ->assertRedirect(route('admin.blog.posts.index'));

        $this->assertDatabaseHas('blog_posts', [
            'title' => 'First admin post',
            'blog_category_id' => $category->id,
            'status' => 'draft',
            'published_at' => null,
        ]);
    }

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

        $category = BlogCategory::query()->create([
            'name' => 'Archive',
            'slug' => 'archive',
            'description' => null,
            'sort_order' => 0,
        ]);

        $backdate = now()->subYears(2)->seconds(0);

        Livewire::actingAs($admin)
            ->test(BlogPostsForm::class)
            ->set('title', 'Historical launch post')
            ->set('content', '<p>'.str_repeat('b', 25).'</p>')
            ->set('status', 'published')
            ->set('published_at_input', $backdate->timezone(config('app.timezone'))->format('Y-m-d\TH:i'))
            ->set('blog_category_id', $category->id)
            ->call('save')
            ->assertHasNoErrors()
            ->assertRedirect(route('admin.blog.posts.index'));

        $post = \App\Models\BlogPost::query()->where('slug', 'historical-launch-post')->firstOrFail();
        $this->assertSame('published', $post->status);
        $this->assertNotNull($post->published_at);
        $this->assertTrue($post->published_at->lessThanOrEqualTo(now()->subYear()));
    }

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

        BlogCategory::query()->delete();

        $this->actingAs($admin)
            ->get(route('admin.blog.posts.create'))
            ->assertOk()
            ->assertSee('Manage categories', false)
            ->assertSee('Posts must belong to a category', false);
    }
}
