<?php

declare(strict_types=1);

namespace Tests\Feature\Academy;

use App\Http\Middleware\ConditionalValidateCsrfToken;
use App\Models\AcademyChallenge;
use App\Models\AcademyChallengeSubmission;
use App\Models\AcademyLesson;
use App\Models\AcademyPromptTemplate;
use App\Models\Artwork;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia;
use Tests\TestCase;

final class AcademyFeatureTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        $this->withoutMiddleware(ConditionalValidateCsrfToken::class);
    }

    public function test_academy_homepage_loads_when_enabled(): void
    {
        $this->get('/academy')
            ->assertOk()
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->component('Academy/Index')
                ->where('featureFlags.paymentsEnabled', false));
    }

    public function test_academy_routes_are_hidden_when_feature_is_disabled(): void
    {
        config(['academy.enabled' => false]);

        $this->get('/academy')->assertNotFound();
        $this->get('/academy/lessons')->assertNotFound();
    }

    public function test_free_lesson_is_visible_to_guest(): void
    {
        $lesson = AcademyLesson::query()->create([
            'title' => 'Free Lesson',
            'slug' => 'free-lesson',
            'excerpt' => 'Visible to guests.',
            'content' => 'Free lesson content',
            'difficulty' => 'beginner',
            'access_level' => 'free',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $this->get(route('academy.lessons.show', ['slug' => $lesson->slug]))
            ->assertOk()
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->component('Academy/Show')
                ->where('item.locked', false)
                ->where('item.content', 'Free lesson content'));
    }

    public function test_creator_lesson_is_locked_for_regular_user(): void
    {
        $lesson = AcademyLesson::query()->create([
            'title' => 'Creator Lesson',
            'slug' => 'creator-lesson',
            'excerpt' => 'Preview only',
            'content' => 'Creator only lesson content',
            'difficulty' => 'intermediate',
            'access_level' => 'creator',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $user = User::factory()->create();

        $this->actingAs($user)
            ->get(route('academy.lessons.show', ['slug' => $lesson->slug]))
            ->assertOk()
            ->assertDontSee('Creator only lesson content')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', true)
                ->where('item.content', null));
    }

    public function test_pro_lesson_is_locked_for_creator_user(): void
    {
        $lesson = AcademyLesson::query()->create([
            'title' => 'Pro Lesson',
            'slug' => 'pro-lesson',
            'excerpt' => 'Pro preview',
            'content' => 'Pro only lesson content',
            'difficulty' => 'pro',
            'access_level' => 'pro',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $creator = User::factory()->create(['role' => 'academy_creator']);

        $this->actingAs($creator)
            ->get(route('academy.lessons.show', ['slug' => $lesson->slug]))
            ->assertOk()
            ->assertDontSee('Pro only lesson content')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', true)
                ->where('item.content', null));
    }

    public function test_premium_prompt_full_text_is_not_exposed_to_unauthorized_users(): void
    {
        $prompt = AcademyPromptTemplate::query()->create([
            'title' => 'Creator Prompt',
            'slug' => 'creator-prompt',
            'excerpt' => 'Locked preview.',
            'prompt' => 'SECRET PREMIUM PROMPT STRING',
            'negative_prompt' => 'SECRET NEGATIVE STRING',
            'difficulty' => 'beginner',
            'access_level' => 'creator',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $this->get(route('academy.prompts.show', ['slug' => $prompt->slug]))
            ->assertOk()
            ->assertDontSee('SECRET PREMIUM PROMPT STRING')
            ->assertDontSee('SECRET NEGATIVE STRING')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', true)
                ->where('item.prompt', null)
                ->where('item.negative_prompt', null));

        $version = app(\App\Http\Middleware\HandleInertiaRequests::class)
            ->version(\Illuminate\Http\Request::create(route('academy.prompts.show', ['slug' => $prompt->slug]), 'GET'));

        $this->withHeaders([
            'X-Inertia' => 'true',
            'X-Requested-With' => 'XMLHttpRequest',
            'X-Inertia-Version' => $version,
        ])->get(route('academy.prompts.show', ['slug' => $prompt->slug]))
            ->assertOk()
            ->assertJsonPath('props.item.locked', true)
            ->assertJsonPath('props.item.prompt', null)
            ->assertJsonPath('props.item.negative_prompt', null)
            ->assertDontSee('SECRET PREMIUM PROMPT STRING')
            ->assertDontSee('SECRET NEGATIVE STRING');
    }

    public function test_authorized_user_can_view_premium_prompt(): void
    {
        $prompt = AcademyPromptTemplate::query()->create([
            'title' => 'Creator Prompt',
            'slug' => 'creator-prompt-allowed',
            'excerpt' => 'Full prompt visible.',
            'prompt' => 'VISIBLE PREMIUM PROMPT',
            'negative_prompt' => 'VISIBLE NEGATIVE PROMPT',
            'difficulty' => 'beginner',
            'access_level' => 'creator',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $creator = User::factory()->create(['role' => 'academy_creator']);

        $this->actingAs($creator)
            ->get(route('academy.prompts.show', ['slug' => $prompt->slug]))
            ->assertOk()
            ->assertSee('VISIBLE PREMIUM PROMPT')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', false)
                ->where('item.prompt', 'VISIBLE PREMIUM PROMPT'));
    }

    public function test_logged_in_user_can_mark_lesson_completed(): void
    {
        $lesson = AcademyLesson::query()->create([
            'title' => 'Trackable Lesson',
            'slug' => 'trackable-lesson',
            'content' => 'Track this lesson',
            'difficulty' => 'beginner',
            'access_level' => 'free',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $user = User::factory()->create();

        $this->actingAs($user)
            ->postJson(route('academy.lessons.complete', ['lesson' => $lesson->id]))
            ->assertOk()
            ->assertJsonPath('completed', true);

        $this->assertDatabaseHas('academy_lesson_progress', [
            'lesson_id' => $lesson->id,
            'user_id' => $user->id,
        ]);
    }

    public function test_logged_in_user_can_save_and_unsave_prompt(): void
    {
        $prompt = AcademyPromptTemplate::query()->create([
            'title' => 'Free Prompt',
            'slug' => 'free-prompt',
            'prompt' => 'Save me',
            'difficulty' => 'beginner',
            'access_level' => 'free',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $user = User::factory()->create();

        $this->actingAs($user)
            ->postJson(route('academy.prompts.save', ['prompt' => $prompt->id]))
            ->assertOk()
            ->assertJsonPath('saved', true);

        $this->assertDatabaseHas('academy_saved_prompts', [
            'prompt_template_id' => $prompt->id,
            'user_id' => $user->id,
        ]);

        $this->actingAs($user)
            ->deleteJson(route('academy.prompts.unsave', ['prompt' => $prompt->id]))
            ->assertOk()
            ->assertJsonPath('saved', false);

        $this->assertDatabaseMissing('academy_saved_prompts', [
            'prompt_template_id' => $prompt->id,
            'user_id' => $user->id,
        ]);
    }

    public function test_logged_in_user_can_submit_artwork_to_active_challenge(): void
    {
        $user = User::factory()->create();
        $artwork = Artwork::factory()->create([
            'user_id' => $user->id,
            'is_public' => true,
            'is_approved' => true,
            'published_at' => now()->subMinute(),
        ]);

        $challenge = AcademyChallenge::query()->create([
            'title' => 'Open Challenge',
            'slug' => 'open-challenge',
            'access_level' => 'free',
            'status' => 'active',
            'active' => true,
            'starts_at' => now()->subHour(),
            'ends_at' => now()->addDay(),
        ]);

        $this->actingAs($user)
            ->post(route('academy.challenges.submit.store', ['slug' => $challenge->slug]), [
                'artwork_id' => $artwork->id,
                'prompt_used' => 'Prompt used',
                'workflow_notes' => 'Workflow notes',
                'ai_tool_used' => 'ComfyUI',
                'is_ai_generated' => true,
                'is_ai_assisted' => true,
            ])
            ->assertRedirect(route('academy.challenges.show', ['slug' => $challenge->slug]));

        $this->assertDatabaseHas('academy_challenge_submissions', [
            'challenge_id' => $challenge->id,
            'user_id' => $user->id,
            'artwork_id' => $artwork->id,
        ]);
    }

    public function test_guest_cannot_view_creator_or_pro_lesson_content(): void
    {
        $creatorLesson = AcademyLesson::query()->create([
            'title' => 'Creator Lesson',
            'slug' => 'guest-creator-lesson',
            'excerpt' => 'Creator preview',
            'content' => 'CREATOR SECRET LESSON BODY',
            'difficulty' => 'advanced',
            'access_level' => 'creator',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $proLesson = AcademyLesson::query()->create([
            'title' => 'Pro Lesson',
            'slug' => 'guest-pro-lesson',
            'excerpt' => 'Pro preview',
            'content' => 'PRO SECRET LESSON BODY',
            'difficulty' => 'pro',
            'access_level' => 'pro',
            'lesson_type' => 'article',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        foreach ([$creatorLesson, $proLesson] as $lesson) {
            $this->get(route('academy.lessons.show', ['slug' => $lesson->slug]))
                ->assertOk()
                ->assertDontSee($lesson->content)
                ->assertInertia(fn (AssertableInertia $page) => $page
                    ->where('item.locked', true)
                    ->where('item.content', null));
        }
    }

    public function test_logged_in_free_user_cannot_view_creator_or_pro_prompt_content(): void
    {
        $creatorPrompt = AcademyPromptTemplate::query()->create([
            'title' => 'Creator Prompt',
            'slug' => 'free-user-creator-prompt',
            'excerpt' => 'Creator preview.',
            'prompt' => 'CREATOR PREMIUM PROMPT',
            'negative_prompt' => 'CREATOR PREMIUM NEGATIVE',
            'difficulty' => 'beginner',
            'access_level' => 'creator',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $proPrompt = AcademyPromptTemplate::query()->create([
            'title' => 'Pro Prompt',
            'slug' => 'free-user-pro-prompt',
            'excerpt' => 'Pro preview.',
            'prompt' => 'PRO PREMIUM PROMPT',
            'negative_prompt' => 'PRO PREMIUM NEGATIVE',
            'difficulty' => 'pro',
            'access_level' => 'pro',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $user = User::factory()->create();

        foreach ([$creatorPrompt, $proPrompt] as $prompt) {
            $this->actingAs($user)
                ->get(route('academy.prompts.show', ['slug' => $prompt->slug]))
                ->assertOk()
                ->assertDontSee($prompt->prompt)
                ->assertDontSee((string) $prompt->negative_prompt)
                ->assertInertia(fn (AssertableInertia $page) => $page
                    ->where('item.locked', true)
                    ->where('item.prompt', null)
                    ->where('item.negative_prompt', null));
        }
    }

    public function test_creator_user_can_view_creator_prompt_but_not_pro_prompt(): void
    {
        $creatorPrompt = AcademyPromptTemplate::query()->create([
            'title' => 'Creator Prompt',
            'slug' => 'creator-visible-prompt',
            'excerpt' => 'Creator prompt.',
            'prompt' => 'CREATOR ACCESS PROMPT',
            'negative_prompt' => 'CREATOR ACCESS NEGATIVE',
            'difficulty' => 'intermediate',
            'access_level' => 'creator',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $proPrompt = AcademyPromptTemplate::query()->create([
            'title' => 'Pro Prompt',
            'slug' => 'creator-locked-pro-prompt',
            'excerpt' => 'Pro prompt.',
            'prompt' => 'PRO ONLY ACCESS PROMPT',
            'negative_prompt' => 'PRO ONLY ACCESS NEGATIVE',
            'difficulty' => 'pro',
            'access_level' => 'pro',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $creator = User::factory()->create(['role' => 'academy_creator']);

        $this->actingAs($creator)
            ->get(route('academy.prompts.show', ['slug' => $creatorPrompt->slug]))
            ->assertOk()
            ->assertSee('CREATOR ACCESS PROMPT')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', false)
                ->where('item.prompt', 'CREATOR ACCESS PROMPT'));

        $this->actingAs($creator)
            ->get(route('academy.prompts.show', ['slug' => $proPrompt->slug]))
            ->assertOk()
            ->assertDontSee('PRO ONLY ACCESS PROMPT')
            ->assertInertia(fn (AssertableInertia $page) => $page
                ->where('item.locked', true)
                ->where('item.prompt', null));
    }

    public function test_pro_and_admin_users_can_view_pro_prompt(): void
    {
        $prompt = AcademyPromptTemplate::query()->create([
            'title' => 'Pro Prompt',
            'slug' => 'pro-visible-prompt',
            'excerpt' => 'Visible to pro and admin.',
            'prompt' => 'VISIBLE TO PRO AND ADMIN',
            'negative_prompt' => 'VISIBLE NEGATIVE TO PRO AND ADMIN',
            'difficulty' => 'pro',
            'access_level' => 'pro',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        foreach ([
            User::factory()->create(['role' => 'academy_pro']),
            User::factory()->create(['role' => 'admin']),
        ] as $user) {
            $this->actingAs($user)
                ->get(route('academy.prompts.show', ['slug' => $prompt->slug]))
                ->assertOk()
                ->assertSee('VISIBLE TO PRO AND ADMIN')
                ->assertInertia(fn (AssertableInertia $page) => $page
                    ->where('item.locked', false)
                    ->where('item.prompt', 'VISIBLE TO PRO AND ADMIN'));
        }
    }

    public function test_challenge_routes_are_hidden_when_challenges_are_disabled(): void
    {
        config(['academy.challenges_enabled' => false]);

        $this->get('/academy/challenges')->assertNotFound();
    }

    public function test_checkout_returns_payment_disabled_response_when_payments_are_disabled(): void
    {
        config(['academy.payments_enabled' => false]);

        $user = User::factory()->create();

        $this->actingAs($user)
            ->postJson(route('academy.checkout', ['plan' => 'creator-monthly']))
            ->assertStatus(423)
            ->assertJsonPath('code', 'academy_payments_disabled');
    }

    public function test_duplicate_prompt_save_is_idempotent(): void
    {
        $prompt = AcademyPromptTemplate::query()->create([
            'title' => 'Free Prompt',
            'slug' => 'idempotent-save-prompt',
            'prompt' => 'Save me twice',
            'difficulty' => 'beginner',
            'access_level' => 'free',
            'active' => true,
            'published_at' => now()->subMinute(),
        ]);

        $user = User::factory()->create();

        $this->actingAs($user)->postJson(route('academy.prompts.save', ['prompt' => $prompt->id]))->assertOk();
        $this->actingAs($user)->postJson(route('academy.prompts.save', ['prompt' => $prompt->id]))->assertOk();

        $this->assertSame(1, DB::table('academy_saved_prompts')->where('user_id', $user->id)->where('prompt_template_id', $prompt->id)->count());
    }

    public function test_duplicate_challenge_submission_updates_existing_record_instead_of_creating_duplicate(): void
    {
        $user = User::factory()->create();
        $artwork = Artwork::factory()->create([
            'user_id' => $user->id,
            'is_public' => true,
            'is_approved' => true,
            'published_at' => now()->subMinute(),
        ]);

        $challenge = AcademyChallenge::query()->create([
            'title' => 'Duplicate Safe Challenge',
            'slug' => 'duplicate-safe-challenge',
            'access_level' => 'free',
            'status' => 'active',
            'active' => true,
            'starts_at' => now()->subHour(),
            'ends_at' => now()->addDay(),
        ]);

        $payload = [
            'artwork_id' => $artwork->id,
            'prompt_used' => 'Prompt one',
            'workflow_notes' => 'Workflow one',
            'ai_tool_used' => 'ComfyUI',
            'is_ai_generated' => true,
            'is_ai_assisted' => true,
        ];

        $this->actingAs($user)->post(route('academy.challenges.submit.store', ['slug' => $challenge->slug]), $payload)->assertRedirect();

        $payload['workflow_notes'] = 'Workflow two';

        $this->actingAs($user)->post(route('academy.challenges.submit.store', ['slug' => $challenge->slug]), $payload)->assertRedirect();

        $this->assertSame(1, DB::table('academy_challenge_submissions')->where('challenge_id', $challenge->id)->where('user_id', $user->id)->where('artwork_id', $artwork->id)->count());
        $this->assertDatabaseHas('academy_challenge_submissions', [
            'challenge_id' => $challenge->id,
            'user_id' => $user->id,
            'artwork_id' => $artwork->id,
            'workflow_notes' => 'Workflow two',
        ]);
    }
}