<?php

use App\Enums\PostStatus;
use App\Models\AdminLog;
use App\Models\Post;
use App\Models\User;
use Livewire\Volt\Volt;

beforeEach(function () {
    $this->admin = User::factory()->admin()->create();
});

// ===========================================
// Index Page Tests
// ===========================================

test('admin can view posts index', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.posts.index'))
        ->assertOk();
});

test('admin can see list of posts', function () {
    $post = Post::factory()->create([
        'title' => ['ar' => 'عنوان عربي', 'en' => 'English Title'],
    ]);

    $this->actingAs($this->admin);

    // Use Volt test to check posts are in the view data (locale independent)
    $component = Volt::test('admin.posts.index');

    expect($component->viewData('posts')->total())->toBe(1);
    expect($component->viewData('posts')->first()->id)->toBe($post->id);
});

test('posts list shows status badges', function () {
    Post::factory()->draft()->create();
    Post::factory()->published()->create();

    $this->actingAs($this->admin);

    $component = Volt::test('admin.posts.index');

    expect($component->viewData('posts')->total())->toBe(2);
});

test('admin can filter posts by status', function () {
    Post::factory()->draft()->create();
    Post::factory()->published()->create();

    $this->actingAs($this->admin);

    $component = Volt::test('admin.posts.index')
        ->set('statusFilter', 'draft');

    expect($component->viewData('posts')->total())->toBe(1);
    expect($component->viewData('posts')->first()->status)->toBe(PostStatus::Draft);
});

test('admin can search posts by title', function () {
    Post::factory()->create(['title' => ['ar' => 'عنوان أول', 'en' => 'First Post']]);
    Post::factory()->create(['title' => ['ar' => 'عنوان ثاني', 'en' => 'Second Post']]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.posts.index')
        ->set('search', 'First');

    expect($component->viewData('posts')->total())->toBe(1);
});

test('admin can search posts by body content', function () {
    Post::factory()->create([
        'title' => ['ar' => 'عنوان أول', 'en' => 'First Post'],
        'body' => ['ar' => 'محتوى فريد', 'en' => 'unique content here'],
    ]);
    Post::factory()->create([
        'title' => ['ar' => 'عنوان ثاني', 'en' => 'Second Post'],
        'body' => ['ar' => 'محتوى آخر', 'en' => 'different content'],
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.posts.index')
        ->set('search', 'unique');

    expect($component->viewData('posts')->total())->toBe(1);
});

test('admin can sort posts by created date', function () {
    $older = Post::factory()->create(['created_at' => now()->subDays(5)]);
    $newer = Post::factory()->create(['created_at' => now()]);

    $this->actingAs($this->admin);

    // Sort by created_at ascending (oldest first)
    $component = Volt::test('admin.posts.index')
        ->call('sort', 'created_at');

    expect($component->viewData('posts')->first()->id)->toBe($older->id);

    // Sort again (descending - newest first)
    $component->call('sort', 'created_at');

    expect($component->viewData('posts')->first()->id)->toBe($newer->id);
});

test('admin can sort posts by updated date', function () {
    $older = Post::factory()->create(['updated_at' => now()->subDays(5)]);
    $newer = Post::factory()->create(['updated_at' => now()]);

    $this->actingAs($this->admin);

    // Default sort is updated_at desc (newest first)
    $component = Volt::test('admin.posts.index');

    expect($component->viewData('posts')->first()->id)->toBe($newer->id);
});

test('admin can toggle post publish status from draft to published', function () {
    $post = Post::factory()->draft()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('togglePublish', $post->id);

    expect($post->fresh()->status)->toBe(PostStatus::Published);
    expect($post->fresh()->published_at)->not->toBeNull();
});

test('admin can toggle post publish status from published to draft', function () {
    $post = Post::factory()->published()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('togglePublish', $post->id);

    expect($post->fresh()->status)->toBe(PostStatus::Draft);
    expect($post->fresh()->published_at)->toBeNull();
});

test('toggle publish creates audit log', function () {
    $post = Post::factory()->draft()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('togglePublish', $post->id);

    expect(AdminLog::where('action', 'status_change')
        ->where('target_type', 'post')
        ->where('target_id', $post->id)
        ->exists())->toBeTrue();

    $log = AdminLog::where('target_id', $post->id)->where('action', 'status_change')->first();
    expect($log->old_values['status'])->toBe('draft');
    expect($log->new_values['status'])->toBe('published');
});

test('admin can delete post from index with confirmation modal', function () {
    $post = Post::factory()->create();
    $postId = $post->id;

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('delete', $post->id)
        ->assertSet('showDeleteModal', true)
        ->assertSet('postToDelete.id', $post->id)
        ->call('confirmDelete');

    expect(Post::find($postId))->toBeNull();
});

test('delete modal shows before deletion', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->assertSet('showDeleteModal', false)
        ->call('delete', $post->id)
        ->assertSet('showDeleteModal', true)
        ->assertSet('postToDelete.id', $post->id);

    // Post should still exist since we haven't confirmed
    expect(Post::find($post->id))->not->toBeNull();
});

test('cancel delete closes modal and keeps post', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('delete', $post->id)
        ->assertSet('showDeleteModal', true)
        ->call('cancelDelete')
        ->assertSet('showDeleteModal', false)
        ->assertSet('postToDelete', null);

    expect(Post::find($post->id))->not->toBeNull();
});

test('delete post creates audit log with old values', function () {
    $post = Post::factory()->create([
        'title' => ['ar' => 'عنوان تجريبي', 'en' => 'Test Title'],
    ]);
    $postId = $post->id;

    $this->actingAs($this->admin);

    Volt::test('admin.posts.index')
        ->call('delete', $post->id)
        ->call('confirmDelete');

    $log = AdminLog::where('action', 'delete')
        ->where('target_type', 'post')
        ->where('target_id', $postId)
        ->first();

    expect($log)->not->toBeNull()
        ->and($log->old_values)->toHaveKey('title')
        ->and($log->old_values['title']['en'])->toBe('Test Title');
});

test('pagination works correctly with per page selector', function () {
    Post::factory()->count(15)->create();

    $this->actingAs($this->admin);

    // Default is 10 per page
    $component = Volt::test('admin.posts.index');
    expect($component->viewData('posts')->perPage())->toBe(10);
    expect($component->viewData('posts')->total())->toBe(15);

    // Change to 25 per page
    $component->set('perPage', 25);
    expect($component->viewData('posts')->perPage())->toBe(25);

    // Change to 50 per page
    $component->set('perPage', 50);
    expect($component->viewData('posts')->perPage())->toBe(50);
});

test('toggle publish handles post not found gracefully', function () {
    $this->actingAs($this->admin);

    // Should not throw exception when post doesn't exist
    Volt::test('admin.posts.index')
        ->call('togglePublish', 99999)
        ->assertOk();
});

test('delete handles post not found gracefully', function () {
    $this->actingAs($this->admin);

    // Should not throw exception when post doesn't exist
    Volt::test('admin.posts.index')
        ->call('delete', 99999)
        ->assertOk();
});

// ===========================================
// Create Page Tests
// ===========================================

test('admin can view post creation form', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.posts.create'))
        ->assertOk();
});

test('admin can create post with valid bilingual content', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان المقال')
        ->set('title_en', 'Article Title')
        ->set('body_ar', '<p>محتوى المقال</p>')
        ->set('body_en', '<p>Article content</p>')
        ->call('saveDraft')
        ->assertHasNoErrors();

    expect(Post::where('title->en', 'Article Title')->exists())->toBeTrue();
});

test('create post fails with missing required fields', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', '')
        ->set('title_en', 'Title')
        ->set('body_ar', 'content')
        ->set('body_en', 'content')
        ->call('save')
        ->assertHasErrors(['title_ar']);
});

test('save draft preserves draft status', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان')
        ->set('title_en', 'Title')
        ->set('body_ar', 'محتوى')
        ->set('body_en', 'Content')
        ->call('saveDraft');

    expect(Post::first()->status)->toBe(PostStatus::Draft);
});

test('publish changes status to published', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان')
        ->set('title_en', 'Title')
        ->set('body_ar', 'محتوى')
        ->set('body_en', 'Content')
        ->call('publish');

    expect(Post::first()->status)->toBe(PostStatus::Published);
    expect(Post::first()->published_at)->not->toBeNull();
});

test('HTML sanitization removes script tags but keeps allowed formatting', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان')
        ->set('title_en', 'Title')
        ->set('body_ar', '<p>نص</p>')
        ->set('body_en', '<p>Safe</p><script>alert("xss")</script><strong>Bold</strong>')
        ->call('saveDraft');

    $post = Post::first();
    expect($post->body['en'])->not->toContain('<script>');
    expect($post->body['en'])->toContain('<strong>Bold</strong>');
});

test('admin log created on post create', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان')
        ->set('title_en', 'Title')
        ->set('body_ar', 'محتوى')
        ->set('body_en', 'Content')
        ->call('saveDraft');

    expect(AdminLog::where('action', 'create')
        ->where('target_type', 'post')
        ->exists())->toBeTrue();
});

test('preview modal can be opened and closed', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->assertSet('showPreview', false)
        ->call('preview')
        ->assertSet('showPreview', true)
        ->call('closePreview')
        ->assertSet('showPreview', false);
});

// ===========================================
// Edit Page Tests
// ===========================================

test('admin can view post edit form', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin)
        ->get(route('admin.posts.edit', $post))
        ->assertOk();
});

test('edit form is populated with existing data', function () {
    $post = Post::factory()->create([
        'title' => ['ar' => 'عنوان قديم', 'en' => 'Old Title'],
        'body' => ['ar' => 'محتوى قديم', 'en' => 'Old Content'],
    ]);

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->assertSet('title_ar', 'عنوان قديم')
        ->assertSet('title_en', 'Old Title')
        ->assertSet('body_ar', 'محتوى قديم')
        ->assertSet('body_en', 'Old Content');
});

test('edit existing post updates content', function () {
    $post = Post::factory()->create(['title' => ['ar' => 'عنوان', 'en' => 'Original']]);

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->set('title_en', 'Updated')
        ->call('save')
        ->assertHasNoErrors();

    expect($post->fresh()->title['en'])->toBe('Updated');
});

test('auto-save only fires for draft posts', function () {
    $post = Post::factory()->published()->create(['title' => ['ar' => 'عنوان', 'en' => 'Original']]);

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->set('title_en', 'Changed')
        ->call('autoSave');

    // Published post should NOT be auto-saved
    expect($post->fresh()->title['en'])->toBe('Original');
});

test('auto-save updates draft posts', function () {
    $post = Post::factory()->draft()->create(['title' => ['ar' => 'عنوان', 'en' => 'Original']]);

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->set('title_en', 'Auto-saved Title')
        ->call('autoSave');

    expect($post->fresh()->title['en'])->toBe('Auto-saved Title');
});

test('admin log created on post update', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->set('title_en', 'Updated Title')
        ->call('save');

    expect(AdminLog::where('action', 'update')
        ->where('target_type', 'post')
        ->where('target_id', $post->id)
        ->exists())->toBeTrue();
});

// ===========================================
// Authorization Tests
// ===========================================

test('non-admin cannot access posts index', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client)
        ->get(route('admin.posts.index'))
        ->assertForbidden();
});

test('non-admin cannot access post creation', function () {
    $client = User::factory()->individual()->create();

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

test('non-admin cannot access post edit', function () {
    $client = User::factory()->individual()->create();
    $post = Post::factory()->create();

    $this->actingAs($client)
        ->get(route('admin.posts.edit', $post))
        ->assertForbidden();
});

test('guest cannot access posts index', function () {
    $this->get(route('admin.posts.index'))
        ->assertRedirect(route('login'));
});

// ===========================================
// Validation Tests
// ===========================================

test('all title fields are required', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', '')
        ->set('title_en', '')
        ->set('body_ar', 'content')
        ->set('body_en', 'content')
        ->call('save')
        ->assertHasErrors(['title_ar', 'title_en']);
});

test('all body fields are required', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.posts.create')
        ->set('title_ar', 'عنوان')
        ->set('title_en', 'Title')
        ->set('body_ar', '')
        ->set('body_en', '')
        ->call('save')
        ->assertHasErrors(['body_ar', 'body_en']);
});

// ===========================================
// Post Model Tests
// ===========================================

test('post has bilingual title accessor', function () {
    $post = Post::factory()->create(['title' => ['ar' => 'عنوان', 'en' => 'Title']]);

    app()->setLocale('ar');
    expect($post->getTitle())->toBe('عنوان');

    app()->setLocale('en');
    expect($post->getTitle())->toBe('Title');
});

test('post has bilingual body accessor', function () {
    $post = Post::factory()->create(['body' => ['ar' => 'محتوى', 'en' => 'Content']]);

    app()->setLocale('ar');
    expect($post->getBody())->toBe('محتوى');

    app()->setLocale('en');
    expect($post->getBody())->toBe('Content');
});

test('post excerpt strips HTML and limits to 150 chars', function () {
    $post = Post::factory()->create(['body' => ['en' => '<p>'.str_repeat('a', 200).'</p>']]);

    expect(strlen($post->getExcerpt('en')))->toBeLessThanOrEqual(153); // 150 + '...'
    expect($post->getExcerpt('en'))->not->toContain('<p>');
});

test('published scope returns only published posts', function () {
    Post::factory()->draft()->create();
    Post::factory()->published()->create();

    expect(Post::published()->count())->toBe(1);
});

test('draft scope returns only draft posts', function () {
    Post::factory()->draft()->create();
    Post::factory()->published()->create();

    expect(Post::draft()->count())->toBe(1);
});

// ===========================================
// Edit Page Delete Tests
// ===========================================

test('edit page shows delete button', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin)
        ->get(route('admin.posts.edit', $post))
        ->assertOk()
        ->assertSee(__('posts.delete_post'));
});

test('admin can delete post from edit page', function () {
    $post = Post::factory()->create();
    $postId = $post->id;

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->call('delete')
        ->assertSet('showDeleteModal', true)
        ->call('confirmDelete')
        ->assertRedirect(route('admin.posts.index'));

    expect(Post::find($postId))->toBeNull();
});

test('edit page delete shows confirmation modal', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->assertSet('showDeleteModal', false)
        ->call('delete')
        ->assertSet('showDeleteModal', true);

    // Post should still exist since we haven't confirmed
    expect(Post::find($post->id))->not->toBeNull();
});

test('edit page cancel delete closes modal', function () {
    $post = Post::factory()->create();

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->call('delete')
        ->assertSet('showDeleteModal', true)
        ->call('cancelDelete')
        ->assertSet('showDeleteModal', false);

    expect(Post::find($post->id))->not->toBeNull();
});

test('edit page delete creates audit log', function () {
    $post = Post::factory()->create([
        'title' => ['ar' => 'عنوان', 'en' => 'Test Title'],
    ]);
    $postId = $post->id;

    $this->actingAs($this->admin);

    Volt::test('admin.posts.edit', ['post' => $post])
        ->call('delete')
        ->call('confirmDelete');

    $log = AdminLog::where('action', 'delete')
        ->where('target_type', 'post')
        ->where('target_id', $postId)
        ->first();

    expect($log)->not->toBeNull()
        ->and($log->old_values)->toHaveKey('title')
        ->and($log->old_values['title']['en'])->toBe('Test Title');
});
