<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;

use App\Models\UserCourse;
use App\Models\Course;
use App\Models\Chapter;
use App\Models\Exercise;
use App\Models\Progress;
use App\Models\UserCourseStatus;

class CourseController extends Controller
{
    // Devuelve el estado del curso para el usuario autenticado.
    function userCourse_status($courseId) {
        // Recupera la petición actual
        $request = request();

        // Recupera la ID del usuario autenticado.
        $userId = Auth::id();

        // Recupera el registro de UserCourse que corresponde al usuario y al curso indicado.
        $userCourse = UserCourse::where('user_id', $userId)
            ->where('course_id', $courseId)
            ->with('status')
            ->first();

        if (!$userCourse || !$userCourse->status) {
            return 'no_record';
        }

        // Output for ajax
        if ($request->expectsJson()) {
            return response()->json($userCourse->status->name);
        }

        // Output for controller
        return $userCourse->status->name;
    }

    // Esta función devuelve la vista con la información del curso.
    public function showCourseInfo($id) {
        // 1) Cargar el curso y las relaciones necesarias (con los usuarios y el pivote 'favorite')
        $course = Course::with(['subcategory.category', 'owner', 'users' => function ($query) {
            $query->withPivot('favorite');
        }])->findOrFail($id);


        // 2) Obtener el estado del curso para el usuario actual
        $courseStatus = $this->userCourse_status($id);

        // 3) Calcular el puntaje del examen si es necesario
        $examScore = null;
        if (in_array($courseStatus, ['Completed', 'Redoing'], true)) {
            // Buscar el capítulo de examen para este curso
            $examChapter = Chapter::where('course_id', $id)
                                    ->where('is_exam', true)
                                    ->first();

            if ($examChapter) {
                $userId = Auth::id();

                // Total de preguntas del examen
                $total = Exercise::where('chapter_id', $examChapter->id)->count();

                // Número de preguntas completadas (status = 'completed' en progresos)
                $done = Progress::where('user_id', $userId)
                                ->whereHas('exercise.chapter', fn($q) => $q->where('id', $examChapter->id))
                                ->where('status', 'completed')
                                ->count();

                $examScore = $total > 0
                        ? round( ($done / $total) * 100 )
                        : 0;
            }
        }

        // 4) Obtener el número de favoritos para este curso
        $favoriteCount = $course->users()->wherePivot('favorite', 1)->count(); // Contar los usuarios con favorite = 1

        // Obtener el id del foro al que pertenece el curso
        $forum = $course->forum;

        // dd($forum->toArray());

        $user = auth()->user();

        // dd($user->toArray());

        // 5) Renderizar la vista incluyendo el puntaje del examen (puede ser nulo)
        return view('pages.student.courseInfo', [
            'course'       => $course,
            'courseStatus' => $courseStatus,
            'examScore'    => $examScore,
            'favoriteCount' => $favoriteCount, // Pasar el contador de favoritos a la vista
            'forum' => $forum, // Pasar el foro a la vista
            'userId' => $user->id, // Pasar el ID del usuario autenticado
        ]);
    }

    // Esta funcion sirve para acceder a un curso, dependiendo del estado hace una cosa o otra.
    public function accessCourse($courseId) {
        // 1) Estado y transiciones
        $status = $this->userCourse_status($courseId);

        if (! in_array($status, ['Owned','In Progress','Completed','Redoing'], true)) {
            abort(403, 'You are not allowed to access this course.');
        }

        if ($status === 'Owned') {
            $status = $this->changeState_userCourse($courseId, 'start');
        } elseif ($status === 'Completed') {
            $status = $this->changeState_userCourse($courseId, 'restart');
        }

        // 2) Recuperar el ID del capítulo actual
        /** @var ProgressController $progressCtrl */
        $progressCtrl     = app(ProgressController::class);
        $currentChapterId = $progressCtrl->current_chapter($courseId);

        // 3) Verificar si el capítulo actual es un examen

        $chapter = Chapter::findOrFail($currentChapterId);
        if ($chapter->is_exam) {
            return redirect()->route('course.chapter.exam', ['chapterId' => $currentChapterId]);
        }

        // 4) Si no es un examen edirigir al método showChapter (GET) para renderizar la vista
        return redirect()->route('course.chapter.show', ['id' => $currentChapterId]);
    }

    // Funcion para mostrar el capitulo por el que va
    public function showChapter($chapterId) {
        // 1) Usuario autenticado
        $userId = Auth::id();

        // 2) Cargar capítulo y course_id
        $chapter  = Chapter::findOrFail($chapterId);
        $courseId = $chapter->course_id;

        // 3) Verificar relación user–course
        $status = $this->userCourse_status($courseId);
        if (! in_array($status, ['In Progress','Redoing'], true)) {
            abort(403, 'You must enroll or start this course before accessing its chapters.');
        }

        // 4) Obtener capítulo actual según progreso
        /** @var ProgressController $progressCtrl */
        $progressCtrl     = app(ProgressController::class);
        $currentChapterId = $progressCtrl->current_chapter($courseId);

        // 5) Validar que no sea un capítulo futuro o un examen
        if ($currentChapterId < $chapterId || $chapter->is_exam) {
            abort(403, 'You cannot access this chapter.');
        }

        // 6) Recuperar todo el contenido + ejercicios
        $chapterData = $progressCtrl->chapter_full($chapterId);

        // 7) Calcular prev/next
        $prev = Chapter::where('course_id', $courseId)
                    ->where('chapter_number', '<',  $chapter->chapter_number)
                    ->orderBy('chapter_number', 'desc')
                    ->first();
        $next = Chapter::where('course_id', $courseId)
                    ->where('chapter_number', '>',  $chapter->chapter_number)
                    ->orderBy('chapter_number', 'asc')
                    ->first();

        // 8) ¿Estamos en el capítulo “actual”?
        $isCurrent = ((int)$currentChapterId === (int)$chapterId);

        // 9) ¿Todos los ejercicios completados?
        $allCompleted = collect($chapterData['exercises'])
            ->every(fn($e) => $e['status'] === 'completed');

        // 10) Cargar info extra para la cabecera
        $course = Course::with(['subcategory.category','owner'])->findOrFail($courseId);

        // 11) Cargamos el progress bar
        $courseProgress = $progressCtrl->course_progress($courseId);

        // 12) Pasar todo a la vista
        return view('pages.student.chapterPage', compact(
            'course',
            'status',
            'chapterData',
            'prev',         // modelo Chapter anterior o null
            'next',         // modelo Chapter siguiente o null
            'isCurrent',    // bool
            'allCompleted',  // bool
            'courseProgress'
        ));
    }

    // Esta funcion sirve para cambiar el progreso y cambiar el estado del curso a uno de los siguientes:
        // - In Progress -> start
        // - Completed -> finish
        // - Redoing -> restart
    public function changeState_userCourse($courseId, $action) {
        $request = request();
        $userId  = Auth::id();

        $map = [
            'start'   => 'In Progress',
            'finish'  => 'Completed',
            'restart' => 'Redoing',
        ];
        if (! isset($map[$action])) {
            abort(400, "Action '{$action}' not supported.");
        }
        $newStatusName = $map[$action];

        $statusModel = UserCourseStatus::where('name', $newStatusName)->firstOrFail();
        $newStatusId = $statusModel->id;

        DB::transaction(function() use($userId, $courseId, $action, $newStatusName) {
            // 1) Actualiza user_course
            $userCourse = UserCourse::updateOrCreate(
                ['user_id' => $userId, 'course_id' => $courseId],
                ['status_id' => UserCourseStatus::where('name', $newStatusName)->firstOrFail()->id]
            );

            // 2) Si es start o restart, inicia progreso del primer capítulo
            if (in_array($action, ['start','restart'])) {
                // Primer capítulo
                $firstChapter = Chapter::where('course_id', $courseId)
                    ->orderBy('chapter_number')
                    ->firstOrFail();

                // Insertamos un registro incompleted por ejercicio
                $exercises = Exercise::where('chapter_id', $firstChapter->id)->get();
                foreach ($exercises as $exercise) {
                    Progress::create([
                        'exercise_id' => $exercise->id,
                        'user_id'     => $userId,
                        'status'      => 'incompleted',
                    ]);
                }
            }
        });

        // 3) Nombre del estado para la respuesta
        $statusName = UserCourseStatus::findOrFail($newStatusId)->name;

        // 4) Respondemos JSON o devolvemos el string
        if ($request->expectsJson()) {
            return response()->json([
                'course_id' => $courseId,
                'status'    => $statusName,
            ]);
        }

        return $statusName;
    }

    // Funcion para mostrar la info del curso
    public function showCourse($id) {
        // Recupera el curso junto con sus relaciones: subcategoría, categoría y owner.
        $course = Course::with(['subcategory.category', 'owner'])->findOrFail($id);

        // Obtiene el estado del curso para el usuario.
        $courseStatus = $this->userCourse_status($id);

        // Pasa la información a la vista.
        return view('pages.student.course', compact('course', 'courseStatus'));
    }

    // Funcion para mostrar el examen
    public function showExam(int $chapterId) {
        $userId = Auth::id();

        // 1) Cargar el capítulo y verificar curso
        $chapter = Chapter::with('course')->findOrFail($chapterId);
        $course  = $chapter->course;

        // 2) Comprobar que el usuario tiene acceso al curso
        $status = $this->userCourse_status($course->id);
        if (! in_array($status, ['In Progress','Redoing'], true)) {
            abort(403, 'You must enroll or start this course before accessing its exam.');
        }

        // 3) Verificar que este capítulo es el actual y es examen
        $progressCtrl       = app(ProgressController::class);
        $currentChapterId   = $progressCtrl->current_chapter($course->id);
        if ($chapterId !== (int)$currentChapterId || ! $chapter->is_exam) {
            abort(403, 'You cannot access this exam now.');
        }

        // 4) Extraer datos del examen (reutilizando chapter_full para ejercicios y opciones)
        $chapterData = $progressCtrl->chapter_full($chapterId);

        // 5) Saber si todos ya fueron intentados (para mostrar Submit)
        $allAttempted = collect($chapterData['exercises'])
            ->every(function($e) {
                return $e['status'] !== 'incompleted';
            });

        // 6) Renderizar la vista
        return view('pages.student.examPage', [
            'course'       => $course,
            'chapterData'  => $chapterData,
            'allAttempted' => $allAttempted,
            // puede pasarse también $status, $prev, $next si lo deseas
        ]);
    }

    // Recibe el POST de finalizar examen
    public function submitExam(Request $request, $chapterId) {
        $userId = Auth::id();

        // 1) Obtenemos el capítulo y su curso
        $chapter  = Chapter::findOrFail($chapterId);
        $courseId = $chapter->course_id;

        // 2) Cambiamos el estado del userCourse a "Completed"
        //    (reutilizamos tu método; asume que devuelve el nombre)
        $this->changeState_userCourse($courseId, 'finish');

        // 3) Calculamos nota del examen
        $exercises = $chapter->exercises()->pluck('id')->toArray();
        $total      = count($exercises);

        // Contamos cuántos progresos quedaron marcados como 'completed'
        $correctos = Progress::where('user_id', $userId)
            ->whereIn('exercise_id', $exercises)
            ->where('status', 'completed')
            ->count();

        // 4) Redirigimos a la vista de nota
        //    le pasamos chapterId, total y correctos
        return redirect()->route('course.chapter.score', [
            'chapterId' => $chapterId,
            'correct'   => $correctos,
            'total'     => $total,
        ]);
    }

    // Muestra la vista con la nota del examen
    public function showScore($chapterId, Request $request) {
        $chapter  = Chapter::findOrFail($chapterId);
        $course   = $chapter->course;
        $correct  = (int) $request->query('correct', 0);
        $total    = (int) $request->query('total', 0);
        $percentage = $total > 0 ? round(100 * $correct / $total) : 0;

        return view('pages.student.examScore', compact(
            'course', 'chapter', 'correct', 'total', 'percentage'
        ));
    }

    // Método que recupera todos los cursos por filtros
    public function getCourses(Request $request) {
        try {
            // Validación automática con mensajes gestionados por Laravel
            $validated = $request->validate([
                'categories'     => ['nullable', 'string', 'regex:/^\d+(,\d+)*$/'],
                'subcategories'  => ['nullable', 'string', 'regex:/^\d+(,\d+)*$/'],
                'types'          => ['nullable', 'string', 'regex:/^[a-zA-Z]+(,[a-zA-Z]+)*$/'],
                'minPrice'       => ['nullable', 'numeric', 'min:0'],
                'maxPrice'       => ['nullable', 'numeric', 'min:0'],
                'page'           => ['nullable', 'integer', 'min:1'],
                'perPage'        => ['nullable', 'integer', 'min:1', 'max:100'],
                'search' => ['nullable', 'string', 'max:255']
            ]);

            $query = Course::query()->with(['subcategory.category']);

            // Únicamente los cursos publicados
            $query->where('status', 'published');

            // Search
            if (!empty($validated['search'])) {
                $query->where('title', 'like', '%' . $validated['search'] . '%');
            }

            // Filtro: Categorías (a través de subcategorías)
            if (!empty($validated['categories'])) {
                $categoryIds = explode(',', $validated['categories']);
                $query->whereHas('subcategory', function ($q) use ($categoryIds) {
                    $q->whereIn('category_id', $categoryIds);
                });
            }

            // Filtro: Subcategorías
            if (!empty($validated['subcategories'])) {
                $subcategoryIds = explode(',', $validated['subcategories']);
                $query->whereIn('subcategory_id', $subcategoryIds);
            }

            // Filtro: Tipos
            if (!empty($validated['types'])) {
                $types = explode(',', $validated['types']);
                $query->whereIn('type', $types);
            }

            // Filtro: Precio
            $minPrice = $validated['minPrice'] ?? 0;
            $maxPrice = $validated['maxPrice'] ?? 100;
            $query->whereBetween('price', [$minPrice, $maxPrice]);

            // NEW: Paginación
            $perPage = $validated['perPage'] ?? 9;
            $courses = $query->paginate($perPage);

            return response()->json([
                'status' => 'success',
                'data' => $courses->items(),
                'pagination' => [
                    'current_page' => $courses->currentPage(),
                    'per_page'     => $courses->perPage(),
                    'total'        => $courses->total(),
                    'last_page'    => $courses->lastPage(),
                ],
            ]);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Validation failed',
                'errors'  => $e->errors(),
            ], 422);
        } catch (\Throwable $e) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Unexpected server error',
                'error'   => $e->getMessage(),
            ], 500);
        }
    }

    // Método para aplicar el favorito a un curso
    public function toggleFavorite(Request $request) {
        try {
            $user = Auth::user();

            $courseId = $request->input('course_id');
            $course = Course::findOrFail($courseId);

            // Verificar si el curso ya tiene relación con el usuario
            $userCourse = $user->courses()->where('course_id', $courseId)->first();

            if ($userCourse) {
                // Si ya existe, cambiamos el valor de favorito
                $newFavoriteStatus = $userCourse->pivot->favorite == 1 ? 0 : 1;
                $userCourse->pivot->update(['favorite' => $newFavoriteStatus]);
            }
            else {
                // Si no existe, lo marcamos como favorito
                $user->courses()->attach($courseId, ['favorite' => 1, 'price_paid' => 0.00]);
                $newFavoriteStatus = 1;
            }

            // Obtener el número actualizado de favoritos para ese curso
            // Aquí estamos usando 'count()' directamente en el modelo Course
            $favoritesCount = $course->users()->wherePivot('favorite', 1)->count();

            return response()->json([
                'success' => true,
                'new_favorites_count' => $favoritesCount,  // Retornamos el nuevo contador
                'isFavorited' => $newFavoriteStatus  // Retornamos el nuevo estado de favorito
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => 'Error al actualizar el favorito: ' . $e->getMessage()
            ], 500);
        }
    }

    public function tops5() {

        // Cursos más "liked" (más usuarios que marcaron favorite = 1)
        $topLiked = Course::select('courses.*')
        ->join('user_courses', 'courses.id', '=', 'user_courses.course_id')
        ->where('user_courses.favorite', 1)
        ->selectRaw('courses.*, COUNT(user_courses.id) as favorite_count')
        ->groupBy('courses.id')
        ->orderByDesc('favorite_count')
        ->take(5)
        ->get();

        // Cursos más comprados (usuarios con status_id = 2)
        $topBought = Course::select('courses.*')
        ->join('user_courses', 'courses.id', '=', 'user_courses.course_id')
        ->where('user_courses.status_id', 2)
        ->selectRaw('courses.*, COUNT(user_courses.id) as purchases_count')
        ->groupBy('courses.id')
        ->orderByDesc('purchases_count')
        ->take(5)
        ->get();

        // Cursos más utilizados (por ejercicios completados)
        $topUsed = Course::select('courses.*')
        ->join('user_courses', 'courses.id', '=', 'user_courses.course_id')
        ->where('user_courses.status_id', 3)
        ->selectRaw('courses.*, COUNT(user_courses.id) as completed_count')
        ->groupBy('courses.id')
        ->orderByDesc('completed_count')
        ->take(5)
        ->get();

        return view('pages.common.bestCourses', ['mostLiked' => $topLiked,'mostBought' => $topBought,'mostUsed' => $topUsed]);
    }

    // Método para crear un nuevo curso
    public function create(Request $request) {
        try {
            // Validar los datos de entrada
            $validated = $request->validate([
                'title' => 'required|string|max:255',
                'description' => 'required|string',
                'subcategory_id' => 'required|int|exists:subcategories,id',
                'category_id' => 'required|int|exists:categories,id',
            ]);


            // Crear el curso
            $course = Course::create([
                'title' => $validated['title'],
                'description' => $validated['description'],
                'subcategory_id' => $validated['subcategory_id'],
                'status' => 'draft', // Estado inicial del curso
                'price' => 0.00, // Precio inicial del curso
                'owner_id' => Auth::id(), // Asignar el ID del usuario autenticado como propietario
            ]);

            // Asignar cover por defecto
            $default_cover = public_path('img/coverIMG/cover_default.jpg');
            $new_cover = public_path('img/coverIMG/cover' . $course->id . '.jpg');

            // Copiar la imagen por defecto a la nueva ubicación
            if (File::exists($default_cover)) {
                File::copy($default_cover, $new_cover);
                // File::copy($default_cover, $new_cover);
            }
            
            return response()->json([
                'success' => true,
                'course' => $course,
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error ' . $e->getMessage(),
            ], 500);
        }

    }

    // Método para actualizar un curso
    public function update(Request $request)
    {
        try {
            // Validar los datos de entrada
            $validated = $request->validate([
                'course_id' => 'required|int|exists:courses,id',
                'title' => 'required|string|max:255',
                'description' => 'required|string',
                'subcategory_id' => 'required|int|exists:subcategories,id',
                'category_id' => 'required|int|exists:categories,id',
                'cover' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
                'status' => 'nullable|in:draft,published,unpublished,review',
            ]);

            $id = $validated['course_id'];

            // Buscar el curso y verificar si el usuario es el propietario
            $course = auth()->user()->coursesIsOwner()->findOrFail($id);

            // Actualizar los campos del curso
            $course->update([
                'title' => $validated['title'],
                'description' => $validated['description'],
                'subcategory_id' => $validated['subcategory_id'],
                'category_id' => $validated['category_id'],
            ]);

            // Si se proporciona un nuevo estado, actualizarlo
            if (isset($validated['status'])) {
                $course->status = $validated['status'];
                $course->save();
            }

            // Si se proporciona una nueva imagen de portada, actualizarla
            if ($request->hasFile('cover')) {
                $cover = $request->file('cover');
                $coverPath = public_path('img/coverIMG/cover' . $id . '.jpg');

                // Eliminar la imagen anterior si existe
                if (File::exists($coverPath)) {
                    File::delete($coverPath);
                }

                // Guardar la nueva imagen
                $cover->move(public_path('img/coverIMG'), 'cover' . $id . '.jpg');
            }

            return response()->json([
                'success' => true,
                'course' => $course,
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error updating course: ' . $e->getMessage(),
            ], 500);
        }
    }

    // Método para destroy un curso
    public function destroy($id) 
    {
        try {
            DB::beginTransaction();

            // 1. Verificar si el usuario es el propietario del curso
            $course = auth()->user()->coursesIsOwner()->findOrFail($id);

            // 2. Eliminar progresos relacionados a los ejercicios de este curso
            foreach ($course->chapters as $chapter) {
                foreach ($chapter->exercises as $exercise) {
                    // Eliminar progresos del ejercicio
                    $exercise->progresses()->delete();
                    // Eliminar opciones del ejercicio
                    $exercise->options()->delete();
                    // Eliminar el ejercicio
                    $exercise->delete();
                }

                // Eliminar el capítulo
                $chapter->delete();
            }

            // 3. Eliminar la relación con los usuarios (tabla pivote user_courses)
            $course->users()->detach();

            // 4. Eliminar la imagen de portada si existe
            $coverPath = public_path('img/coverIMG/cover' . $id . '.jpg');
            if (File::exists($coverPath)) {
                File::delete($coverPath);
            }

            // 5. Eliminar el curso
            $course->delete();

            // 6. Commit de la transacción
            DB::commit();

            return redirect()->route('teacher.dashboard')->with('success', 'Course deleted successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->route('teacher.dashboard')->with('error', 'Error deleting course: ' . $e->getMessage());
        }
    }
}