<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Services\CourseContentService;
use App\Services\CourseService;
use App\Services\EnrollmentService;
use App\Services\CertificateService;
use App\Services\CommunicationService;

class LearningController extends Controller
{
    private CourseService $courses;
    private CourseContentService $content;
    private EnrollmentService $enrollments;
    private CertificateService $certificates;
    private CommunicationService $communication;

    public function __construct()
    {
        $this->courses = new CourseService();
        $this->content = new CourseContentService();
        $this->enrollments = new EnrollmentService();
        $this->certificates = new CertificateService();
        $this->communication = new CommunicationService();
    }

    public function enroll(Request $request): void
    {
        require_auth();

        if (!verify_csrf((string) $request->post('_csrf_token', ''))) {
            flash('error', 'Sessao expirada. Tente novamente.');
            app()->response()->back();
        }

        $result = $this->enrollments->enrollFree((int) $request->post('course_id'), current_user());

        if (!$result['ok']) {
            flash('error', $result['error']);
            app()->response()->back();
        }

        flash('success', 'Inscricao feita. Bom estudo!');
        app()->response()->redirect('/learn/course?id=' . $request->post('course_id'));
    }

    public function myCourses(): string
    {
        require_role('student');

        $items = array_map(function (array $item): array {
            $enrollment = $item['enrollment'];
            $item['certificate'] = $this->certificates->findByEnrollment((int) $enrollment['id']);
            $item['certificate_eligibility'] = $this->certificates->eligibilityForEnrollment($enrollment);

            return $item;
        }, $this->enrollments->enrolledCourses((int) current_user()['id']));

        return $this->view('learning/my-courses', [
            'title' => 'Meus cursos',
            'items' => $items,
        ]);
    }

    public function course(Request $request): string
    {
        require_role('student');
        $courseId = (int) $request->input('id');
        $course = $this->courses->find($courseId);
        $enrollment = $this->enrollments->findEnrollment((int) current_user()['id'], $courseId);

        if (!$course || !$enrollment) {
            flash('error', 'Nao tem acesso a este curso.');
            app()->response()->redirect('/student/courses');
        }

        $lessonId = (int) ($enrollment['last_lesson_id'] ?? 0) ?: ($this->enrollments->firstLessonId($courseId) ?? 0);

        if ($lessonId > 0) {
            app()->response()->redirect('/learn/lesson?lesson_id=' . $lessonId);
        }

        return $this->view('learning/course-empty', [
            'title' => $course['title'],
            'course' => $course,
        ]);
    }

    public function lesson(Request $request): string
    {
        require_role('student');
        $lesson = $this->content->lesson((int) $request->input('lesson_id'));

        if (!$lesson) {
            flash('error', 'Aula nao encontrada.');
            app()->response()->redirect('/student/courses');
        }

        $course = $this->courses->find((int) $lesson['course_id']);
        $enrollment = $this->enrollments->findEnrollment((int) current_user()['id'], (int) $lesson['course_id']);

        if (!$course || !$enrollment) {
            flash('error', 'Nao tem acesso a esta aula.');
            app()->response()->redirect('/student/courses');
        }

        $this->enrollments->touchEnrollment((int) $enrollment['id'], ['last_lesson_id' => (int) $lesson['id']]);

        return $this->view('learning/player', [
            'title' => $lesson['title'],
            'course' => $course,
            'sections' => $this->content->courseContent((int) $course['id']),
            'lesson' => $lesson,
            'enrollment' => $enrollment,
            'progress' => $this->enrollments->courseProgress((int) $enrollment['id']),
            'lessonProgress' => $this->enrollments->lessonProgress((int) $enrollment['id'], (int) $lesson['id']),
            'completedLessonIds' => $this->enrollments->completedLessonIds((int) $enrollment['id']),
            'isCompleted' => $this->enrollments->lessonCompleted((int) $enrollment['id'], (int) $lesson['id']),
            'previousLessonId' => $this->enrollments->previousLessonId((int) $course['id'], (int) $lesson['id']),
            'nextLessonId' => $this->enrollments->nextLessonId((int) $course['id'], (int) $lesson['id']),
            'questions' => $this->communication->questionsForLesson((int) $lesson['id']),
        ]);
    }

    public function complete(Request $request): void
    {
        require_role('student');

        if (!verify_csrf((string) $request->post('_csrf_token', ''))) {
            flash('error', 'Sessao expirada. Tente novamente.');
            app()->response()->back();
        }

        $result = $this->enrollments->markCompleted(
            (int) $request->post('enrollment_id'),
            (int) $request->post('lesson_id'),
            (int) current_user()['id']
        );

        flash($result['ok'] ? 'success' : 'error', $result['ok'] ? 'Aula marcada como concluida.' : $result['error']);
        app()->response()->back();
    }

    public function progress(Request $request): void
    {
        require_role('student');

        header('Content-Type: application/json');

        if (!verify_csrf((string) $request->post('_csrf_token', ''))) {
            http_response_code(419);
            echo json_encode(['ok' => false, 'error' => 'Sessao expirada.']);
            return;
        }

        $result = $this->enrollments->saveWatchPosition(
            (int) $request->post('enrollment_id'),
            (int) $request->post('lesson_id'),
            (int) current_user()['id'],
            (int) $request->post('second', 0)
        );

        http_response_code($result['ok'] ? 200 : 422);
        echo json_encode($result);
    }
}
