<?php

namespace Tests\Feature;

use App\Livewire\CoursePlayer;
use App\Models\Course;
use App\Models\Lesson;
use App\Models\User;
use Database\Seeders\CourseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class CoursePlayerTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed(CourseSeeder::class);
    }

    private function course(): Course
    {
        return Course::where('slug', 'investable')->firstOrFail();
    }

    public function test_guest_can_watch_free_preview_lesson(): void
    {
        $preview = $this->course()->lessons()->where('is_free_preview', true)->firstOrFail();

        $this->get(route('learn.lesson', ['course' => 'investable', 'lesson' => $preview->slug]))
            ->assertOk()
            ->assertSee($preview->title);
    }

    public function test_locked_lesson_requires_enrollment(): void
    {
        $locked = $this->course()->lessons()->where('is_free_preview', false)->firstOrFail();
        $user = User::factory()->create();

        $this->actingAs($user)
            ->get(route('learn.lesson', ['course' => 'investable', 'lesson' => $locked->slug]))
            ->assertForbidden();
    }

    public function test_user_can_enroll_and_access_all_lessons(): void
    {
        $user = User::factory()->create();
        $course = $this->course();

        $this->actingAs($user)
            ->post(route('learn.enroll', $course))
            ->assertRedirect();

        $this->assertDatabaseHas('enrollments', ['user_id' => $user->id, 'course_id' => $course->id]);

        $locked = $course->lessons()->where('is_free_preview', false)->firstOrFail();

        $this->actingAs($user)
            ->get(route('learn.lesson', ['course' => 'investable', 'lesson' => $locked->slug]))
            ->assertOk();
    }

    public function test_completing_lessons_updates_enrollment_progress(): void
    {
        $user = User::factory()->create();
        $course = $this->course();

        $this->actingAs($user)->post(route('learn.enroll', $course));

        $first = $course->lessons()->first();

        Livewire::actingAs($user)
            ->test(CoursePlayer::class, ['course' => $course, 'lesson' => $first])
            ->call('toggleComplete');

        $enrollment = $user->enrollments()->where('course_id', $course->id)->first();
        $expected = (int) round(1 / $course->lessons()->count() * 100);

        $this->assertSame($expected, $enrollment->progress);
        $this->assertTrue($user->completedLessons()->where('lessons.id', $first->id)->exists());

        // Toggle off removes it again
        Livewire::actingAs($user)
            ->test(CoursePlayer::class, ['course' => $course, 'lesson' => $first])
            ->call('toggleComplete');

        $this->assertSame(0, $enrollment->fresh()->progress);
    }

    public function test_complete_and_continue_advances_to_next_lesson(): void
    {
        $user = User::factory()->create();
        $course = $this->course();

        $this->actingAs($user)->post(route('learn.enroll', $course));

        $ordered = $course->modules()->with('lessons')->get()->flatMap->lessons->values();
        $first = $ordered->get(0);
        $second = $ordered->get(1);

        Livewire::actingAs($user)
            ->test(CoursePlayer::class, ['course' => $course, 'lesson' => Lesson::find($first->id)])
            ->call('completeAndContinue')
            ->assertRedirect(route('learn.lesson', ['course' => $course->slug, 'lesson' => $second->slug]));
    }
}
