<?php

declare(strict_types=1);

use App\Models\ArticleVote;
use App\Models\KnowledgeBaseArticle;
use App\Models\KnowledgeBaseCategory;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;

beforeEach(function (): void {
    $this->seed(RoleAndPermissionSeeder::class);
    $this->adminUrl = 'http://'.config('app.domains.admin');
    $this->marketingUrl = 'http://'.config('app.domains.marketing');
});

/*
|--------------------------------------------------------------------------
| Admin KB Category Tests
|--------------------------------------------------------------------------
*/

test('admin can list kb categories', function (): void {
    $admin = User::factory()->admin()->create();

    KnowledgeBaseCategory::factory()->count(3)->create();

    $this->actingAs($admin)
        ->get($this->adminUrl.'/knowledge-base/categories')
        ->assertOk();
});

test('admin can create kb category', function (): void {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl.'/knowledge-base/categories/create')
        ->assertOk();
});

test('admin can store kb category', function (): void {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->post($this->adminUrl.'/knowledge-base/categories', [
            'name' => 'Getting Started',
            'slug' => 'getting-started',
            'description' => 'Beginner guides',
            'icon' => 'tabler-rocket',
            'sort_order' => 0,
            'is_visible' => true,
        ])
        ->assertRedirect();

    $this->assertDatabaseHas('knowledge_base_categories', [
        'name' => 'Getting Started',
        'slug' => 'getting-started',
    ]);
});

test('admin can edit kb category', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl."/knowledge-base/categories/{$category->id}/edit")
        ->assertOk();
});

test('admin can update kb category', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->put($this->adminUrl."/knowledge-base/categories/{$category->id}", [
            'name' => 'Updated Name',
            'slug' => $category->slug,
            'sort_order' => 5,
            'is_visible' => true,
        ])
        ->assertRedirect();

    $this->assertDatabaseHas('knowledge_base_categories', [
        'id' => $category->id,
        'name' => 'Updated Name',
        'sort_order' => 5,
    ]);
});

test('admin cannot delete category with articles', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();
    KnowledgeBaseArticle::factory()->create(['category_id' => $category->id]);

    $this->actingAs($admin)
        ->delete($this->adminUrl."/knowledge-base/categories/{$category->id}")
        ->assertRedirect();

    $this->assertDatabaseHas('knowledge_base_categories', ['id' => $category->id]);
});

test('admin can delete empty category', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->delete($this->adminUrl."/knowledge-base/categories/{$category->id}")
        ->assertRedirect();

    $this->assertDatabaseMissing('knowledge_base_categories', ['id' => $category->id]);
});

/*
|--------------------------------------------------------------------------
| Admin KB Article Tests
|--------------------------------------------------------------------------
*/

test('admin can list kb articles', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();
    KnowledgeBaseArticle::factory()->count(3)->create(['category_id' => $category->id]);

    $this->actingAs($admin)
        ->get($this->adminUrl.'/knowledge-base/articles')
        ->assertOk();
});

test('admin can filter kb articles by status', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();
    KnowledgeBaseArticle::factory()->published()->create(['category_id' => $category->id]);
    KnowledgeBaseArticle::factory()->draft()->create(['category_id' => $category->id]);

    $this->actingAs($admin)
        ->get($this->adminUrl.'/knowledge-base/articles?status=published')
        ->assertOk();
});

test('admin can create kb article', function (): void {
    $admin = User::factory()->admin()->create();
    KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl.'/knowledge-base/articles/create')
        ->assertOk();
});

test('admin can store kb article', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->post($this->adminUrl.'/knowledge-base/articles', [
            'title' => 'How to Set Up Your VPS',
            'slug' => 'how-to-set-up-your-vps',
            'category_id' => $category->id,
            'content' => '# Getting Started\n\nThis guide walks you through setting up your VPS.',
            'excerpt' => 'A beginner guide to VPS setup.',
            'status' => 'draft',
            'is_featured' => false,
        ])
        ->assertRedirect();

    $this->assertDatabaseHas('knowledge_base_articles', [
        'title' => 'How to Set Up Your VPS',
        'slug' => 'how-to-set-up-your-vps',
        'author_id' => $admin->id,
        'status' => 'draft',
    ]);

    $article = KnowledgeBaseArticle::query()->where('slug', 'how-to-set-up-your-vps')->first();
    expect($article->revisions()->count())->toBe(1);
});

test('admin store article with published status sets published_at', function (): void {
    $admin = User::factory()->admin()->create();
    $category = KnowledgeBaseCategory::factory()->create();

    $this->actingAs($admin)
        ->post($this->adminUrl.'/knowledge-base/articles', [
            'title' => 'Published Article',
            'slug' => 'published-article',
            'category_id' => $category->id,
            'content' => 'Some content here.',
            'status' => 'published',
            'is_featured' => false,
        ])
        ->assertRedirect();

    $article = KnowledgeBaseArticle::query()->where('slug', 'published-article')->first();
    expect($article->published_at)->not->toBeNull();
});

test('admin can view kb article', function (): void {
    $admin = User::factory()->admin()->create();
    $article = KnowledgeBaseArticle::factory()->published()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl."/knowledge-base/articles/{$article->id}")
        ->assertOk();
});

test('admin can edit kb article', function (): void {
    $admin = User::factory()->admin()->create();
    $article = KnowledgeBaseArticle::factory()->create();

    $this->actingAs($admin)
        ->get($this->adminUrl."/knowledge-base/articles/{$article->id}/edit")
        ->assertOk();
});

test('admin can update kb article', function (): void {
    $admin = User::factory()->admin()->create();
    $article = KnowledgeBaseArticle::factory()->create();

    $this->actingAs($admin)
        ->put($this->adminUrl."/knowledge-base/articles/{$article->id}", [
            'title' => 'Updated Title',
            'slug' => $article->slug,
            'category_id' => $article->category_id,
            'content' => 'Updated content.',
            'status' => $article->status,
            'is_featured' => false,
        ])
        ->assertRedirect();

    $this->assertDatabaseHas('knowledge_base_articles', [
        'id' => $article->id,
        'title' => 'Updated Title',
    ]);

    expect($article->revisions()->count())->toBe(1);
});

test('admin can delete kb article', function (): void {
    $admin = User::factory()->admin()->create();
    $article = KnowledgeBaseArticle::factory()->create();

    $this->actingAs($admin)
        ->delete($this->adminUrl."/knowledge-base/articles/{$article->id}")
        ->assertRedirect();

    $this->assertDatabaseMissing('knowledge_base_articles', ['id' => $article->id]);
});

/*
|--------------------------------------------------------------------------
| Marketing KB Tests
|--------------------------------------------------------------------------
*/

test('kb homepage shows categories and featured articles', function (): void {
    $category = KnowledgeBaseCategory::factory()->create(['is_visible' => true]);
    KnowledgeBaseArticle::factory()->featured()->create(['category_id' => $category->id]);

    $this->get($this->marketingUrl.'/knowledge-base')
        ->assertOk();
});

test('kb category page shows articles', function (): void {
    $category = KnowledgeBaseCategory::factory()->create(['is_visible' => true]);
    KnowledgeBaseArticle::factory()->published()->count(3)->create(['category_id' => $category->id]);

    $this->get($this->marketingUrl."/knowledge-base/{$category->slug}")
        ->assertOk();
});

test('kb article page renders and increments view count', function (): void {
    $category = KnowledgeBaseCategory::factory()->create(['is_visible' => true]);
    $article = KnowledgeBaseArticle::factory()->published()->create([
        'category_id' => $category->id,
        'view_count' => 10,
    ]);

    $this->get($this->marketingUrl."/knowledge-base/{$category->slug}/{$article->slug}")
        ->assertOk();

    $article->refresh();
    expect($article->view_count)->toBe(11);
});

test('kb search returns matching articles', function (): void {
    $category = KnowledgeBaseCategory::factory()->create();
    KnowledgeBaseArticle::factory()->published()->create([
        'category_id' => $category->id,
        'title' => 'How to configure DNS settings',
        'content' => 'This article explains DNS configuration for your domains.',
    ]);

    $this->getJson($this->marketingUrl.'/knowledge-base/search?q=DNS')
        ->assertOk()
        ->assertJsonStructure(['articles']);
});

test('kb vote creates vote and updates counts', function (): void {
    $category = KnowledgeBaseCategory::factory()->create();
    $article = KnowledgeBaseArticle::factory()->published()->create([
        'category_id' => $category->id,
        'helpful_count' => 0,
        'not_helpful_count' => 0,
    ]);

    $this->postJson($this->marketingUrl."/knowledge-base/articles/{$article->id}/vote", [
        'is_helpful' => true,
    ])->assertOk();

    $article->refresh();
    expect($article->helpful_count)->toBe(1);
    expect($article->not_helpful_count)->toBe(0);

    expect(ArticleVote::query()->where('article_id', $article->id)->count())->toBe(1);
});

test('kb vote prevents duplicate from same ip', function (): void {
    $category = KnowledgeBaseCategory::factory()->create();
    $article = KnowledgeBaseArticle::factory()->published()->create([
        'category_id' => $category->id,
        'helpful_count' => 0,
        'not_helpful_count' => 0,
    ]);

    $this->postJson($this->marketingUrl."/knowledge-base/articles/{$article->id}/vote", [
        'is_helpful' => true,
    ])->assertOk();

    $this->postJson($this->marketingUrl."/knowledge-base/articles/{$article->id}/vote", [
        'is_helpful' => true,
    ])->assertOk();

    $article->refresh();
    expect($article->helpful_count)->toBe(1);
});

test('kb unpublished article returns 404', function (): void {
    $category = KnowledgeBaseCategory::factory()->create(['is_visible' => true]);
    $article = KnowledgeBaseArticle::factory()->draft()->create([
        'category_id' => $category->id,
    ]);

    $this->get($this->marketingUrl."/knowledge-base/{$category->slug}/{$article->slug}")
        ->assertNotFound();
});

/*
|--------------------------------------------------------------------------
| Model Tests
|--------------------------------------------------------------------------
*/

test('article helpful percentage calculation', function (): void {
    $article = KnowledgeBaseArticle::factory()->make([
        'helpful_count' => 8,
        'not_helpful_count' => 2,
    ]);

    expect($article->helpfulPercentage())->toBe(80.0);
});

test('article helpful percentage returns zero for no votes', function (): void {
    $article = KnowledgeBaseArticle::factory()->make([
        'helpful_count' => 0,
        'not_helpful_count' => 0,
    ]);

    expect($article->helpfulPercentage())->toBe(0.0);
});

test('category get ancestors returns parent chain', function (): void {
    $grandparent = KnowledgeBaseCategory::factory()->create(['name' => 'Grandparent']);
    $parent = KnowledgeBaseCategory::factory()->create(['name' => 'Parent', 'parent_id' => $grandparent->id]);
    $child = KnowledgeBaseCategory::factory()->create(['name' => 'Child', 'parent_id' => $parent->id]);

    $ancestors = $child->getAncestors();

    expect($ancestors)->toHaveCount(2);
    expect($ancestors->first()->name)->toBe('Grandparent');
    expect($ancestors->last()->name)->toBe('Parent');
});

test('category scopes work correctly', function (): void {
    KnowledgeBaseCategory::factory()->create(['is_visible' => true, 'parent_id' => null]);
    KnowledgeBaseCategory::factory()->create(['is_visible' => false, 'parent_id' => null]);

    $parentCategory = KnowledgeBaseCategory::factory()->create(['is_visible' => true]);
    KnowledgeBaseCategory::factory()->create(['is_visible' => true, 'parent_id' => $parentCategory->id]);

    expect(KnowledgeBaseCategory::query()->visible()->count())->toBe(3);
    expect(KnowledgeBaseCategory::query()->root()->count())->toBe(3);
});
