<?php

namespace App\Http\Controllers;

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

use App\Models\Chapter;
use App\Models\Progress;
use App\Models\Exercise;
use App\Models\Option;

class ProgressController extends Controller
{
    // Devuelve el id del capítulo por el que va el usuario en un curso específico.
    public function current_chapter($courseId) {   
        // Recupera la petición actual
        $request = request();

        // Recuperar id del usuario autenticado
        $userId = Auth::id();

        // Obtiene un único registro de progreso que corresponda al usuario y al curso indicado.
        $progress = Progress::where('user_id', $userId)
            ->whereHas('exercise.chapter', function($query) use ($courseId) {
                $query->where('course_id', $courseId);
            })
            ->first();
        
        // Si no se encuentra progreso, devuelve un error 404.
        if (!$progress) {
            abort(404, 'No progress found for this course.');
        }

        // Extrae el chapter_id a través de la relación: progreso -> ejercicio -> capítulo.
        $currentChapterId = $progress->exercise->chapter->id;

        // Output for ajax
        if ($request->expectsJson()) {
            return response()->json([
                'current_chapter_id' => $currentChapterId
            ]);
        }

        // Output for controller
        return $currentChapterId;
    }

    // Devuelve el estado de cada ejercicio del capitulo
    public function chapter_exercises($chapterId) {
        // Recupera la petición actual
        $request = request();

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

        // Recuperamos todos los ejercicios del capitulo 
        $exercises = Exercise::where('chapter_id', $chapterId)
            ->whereHas('progresses', function($query) use ($userId) {
                $query->where('user_id', $userId);
            })
            ->with(['progresses' => function($query) use ($userId) {
                $query->where('user_id', $userId);
            }])
            ->get();
        
        // Si no se encuentra progreso, devuelve un error 404.
        if ($exercises->isEmpty()) {
            abort(404, 'No progress found for this chapter.');
        }

        // Mapea cada ejercicio para incluir su estado.
        $exercisesStatus = $exercises->map(function ($exercise) {
            $progressRecord = $exercise->progresses->first();
            $status = $progressRecord->status;

            return [
                'exercise_id'     => $exercise->id,
                'status'          => $status
            ];
        });

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

        // Output for controller
        return $exercisesStatus;
    }

    // Api que recupera el progreso entero de un curso
    public function course_progress($courseId) {
        $request = request();
        $userId = Auth::id();
    
        // Obtenemos todos los capítulos del curso con sus ejercicios
        $chapters = Chapter::where('course_id', $courseId)
            ->with('exercises')
            ->get();
    
        if ($chapters->isEmpty()) {
            abort(404, 'No chapters found for this course.');
        }
    
        $chapterProgress = $chapters->map(function ($chapter) use ($userId) {
            $hasProgress = $chapter->exercises->contains(function ($exercise) use ($userId) {
                return $exercise->progresses()->where('user_id', $userId)->exists();
            });
    
            return [
                'chapter_id'    => $chapter->id,
                'chapter_number' => $chapter->chapter_number,
                'chapter_title' => $chapter->title,
                'is_exam'       => $chapter->is_exam, // ← Campo asumido en base de datos
                'has_progress'  => $hasProgress
            ];
        });
    
        if ($request->expectsJson()) {
            return response()->json($chapterProgress);
        }
    
        return $chapterProgress;
    }


    // Devuelve toda la info del capitulo junto a sus ejercicios (la respuesta solo el de los completados)
        // - comprueba si el capitulo es por el que va, si es anterior devuelve directamente todo, si va por ese hace las comprobaciones de abajo, si es mas alante no recupera nada y pone que no puede
        // - recupera toda la info del capitulo
        // - recupera todos los ejercicios con sus respuestas (si estan completados recupera la solucion de cada uno)
    public function chapter_full($chapterId) {
        $request          = request();
        $userId           = Auth::id();
        $chapter          = Chapter::findOrFail($chapterId);
        $courseId         = $chapter->course_id;
        $currentChapterId = $this->current_chapter($courseId);
    
        // 1) Acceso
        if ($currentChapterId < $chapterId) {
            $msg = ['message' => 'You cannot access this chapter yet.'];
            return $request->expectsJson()
                ? response()->json($msg, 403)
                : $msg;
        }
    
        // 2) Lista de ejercicios a procesar
        if ($currentChapterId == $chapterId) {
            // Capítulo en curso: sólo los ejercicios con progreso real
            $exerciseStatusList = $this->chapter_exercises($chapterId)
                ->map(fn($e) => [
                    'exercise_id' => $e['exercise_id'],
                    'status'      => $e['status'],
                ])->toArray();
        } else {
            // Capítulo anterior: todos los ejercicios, asumidos completados
            $exerciseStatusList = Exercise::where('chapter_id', $chapterId)
                ->get()
                ->map(fn($ex) => [
                    'exercise_id'     => $ex->id,
                    'status'          => 'completed',
                ])->toArray();
        }
    
        // 3) Payload base
        $payload = [
            'chapter_id'     => $chapter->id,
            'chapter_number' => $chapter->chapter_number,
            'title'          => $chapter->title,
            'description'    => $chapter->description,
            'content'        => $chapter->content,
            'exercises'      => [],
        ];
    
        // 4) Recorrer ejercicios
        foreach ($exerciseStatusList as $exeData) {
            $exercise = Exercise::findOrFail($exeData['exercise_id']);
            $status   = $exeData['status'];
    
            $item = [
                'exercise_id'     => $exercise->id,
                'exercise_number' => $exercise->exercise_number,
                'question'        => $exercise->question ?? $exercise->content,
                'type'            => $exercise->type,
                'status'          => $status,
            ];
    
            // 5) Opciones: si es “input”, devolver la respuesta correcta como value;
            //    si es radio/checkbox, devolver todas marcando la correcta.
            if ($exercise->type === 'input') {
                // Busca la opción correcta y la muestra como value
                $opt = Option::where('exercise_id', $exercise->id)
                                ->where('is_correct', true)
                                ->first();
                $item['options'] = $status === 'completed'
                    ? [['option_id' => $opt->id, 'answer' => $opt->answer, 'is_correct' => true]]
                    : [];
            } else {
                // radio o checkbox → siempre listamos todas
                $opts = Option::where('exercise_id', $exercise->id)->get();
                $item['options'] = $opts->map(fn($o) => [
                    'option_id' => $o->id,
                    'answer'    => $o->answer,
                    // sólo mostramos is_correct si el ejercicio está completado
                    ...($status === 'completed' ? ['is_correct' => (bool)$o->is_correct] : [])
                ])->toArray();
            }
    
            $payload['exercises'][] = $item;
        }
    
        // 6) Respuesta
        return $request->expectsJson()
            ? response()->json($payload)
            : $payload;
    }        

    // Funcion para responder un ejercicio de cualquier tipo
    public function answerExercise(Request $request) {
        $request->validate([
            'exercise_id' => 'required|integer|exists:exercises,id',
            'answer'      => 'required',  // string, int or array depending on type
        ]);

        $userId     = Auth::id();
        $exerciseId = $request->input('exercise_id');
        $answer     = $request->input('answer');

        $exercise = \App\Models\Exercise::with('chapter')->findOrFail($exerciseId);
        $type     = $exercise->type;
        $isExam   = $exercise->chapter->is_exam;

        // 1) Determine correctness
        $correct = false;

        if ($type === 'input') {
            $opt = Option::where('exercise_id', $exerciseId)
                        ->where('is_correct', true)
                        ->first();
            $correct = $opt
                && mb_strtolower(trim($opt->answer)) === mb_strtolower(trim($answer));

        } elseif ($type === 'radio') {
            $correct = Option::where('exercise_id', $exerciseId)
                            ->where('id', $answer)
                            ->where('is_correct', true)
                            ->exists();

        } else { // checkbox
            $selected   = (array) $answer;
            $correctIds = Option::where('exercise_id', $exerciseId)
                                ->where('is_correct', true)
                                ->pluck('id')
                                ->sort()
                                ->values()
                                ->toArray();
            sort($selected);
            $correct = $selected === $correctIds;
        }

        // 2) If not exam and incorrect, reject immediately
        if (! $isExam && ! $correct) {
            return response()->json([
                'success' => false,
                'message' => 'That answer is incorrect, please try again.'
            ], 422);
        }

        // 3) Persist progress (completed or incorrect)
        Progress::updateOrCreate(
            ['user_id'     => $userId, 'exercise_id' => $exerciseId],
            ['status'      => $correct ? 'completed' : 'incorrect']
        );

        // 4) Non‐exam: return JSON + allCompleted flag
        if (! $isExam) {
            $chapterId = $exercise->chapter_id;
            $total     = \App\Models\Exercise::where('chapter_id', $chapterId)->count();
            $done      = Progress::where('user_id', $userId)
                                ->whereHas('exercise', fn($q) => $q->where('chapter_id', $chapterId))
                                ->where('status', 'completed')
                                ->count();
            $allDone   = ($total === $done);

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

        // 5) Exam exercise: do not reveal correctness, just 204 No Content
        return response()->noContent();
    }
    
    // Avanza al siguiente capitulo
    public function nextChapter($chapterId) {
        $userId = Auth::id();

        // 1) Verificar que todos los ejercicios actuales estén completados
        $exStatuses      = $this->chapter_exercises($chapterId);
        $allCompleted    = collect($exStatuses)
                             ->every(fn($e) => $e['status'] === 'completed');

        if (! $allCompleted) {
            abort(400, 'You must complete all exercises before moving on.');
        }

        // 2) Localizar el capítulo actual y el siguiente
        $current = Chapter::findOrFail($chapterId);
        $courseId = $current->course_id;

        $next = Chapter::where('course_id', $courseId)
                       ->where('chapter_number', '>', $current->chapter_number)
                       ->orderBy('chapter_number')
                       ->first();

        if (! $next) {
            abort(404, 'There is no next chapter.');
        }

        // 3) Verificar si estamos rehaciendo (Redoing) y el siguiente es un examen
        /** @var CourseController $courseCtrl */
        $courseCtrl   = app(CourseController::class);
        $courseStatus = $courseCtrl->userCourse_status($courseId);

        if ($courseStatus === 'Redoing' && $next->is_exam) {
            DB::transaction(function() use ($userId, $courseId, $courseCtrl) {
                // a) Borrar todos los Progress de capítulos que NO son examen
                Progress::where('user_id', $userId)
                    ->whereHas('exercise.chapter', fn($q) => $q->where('is_exam', false))
                    ->delete();

                // b) Cambiar el estado del curso a Completed
                $courseCtrl->changeState_userCourse($courseId, 'finish');
            });

            // Redirigir a la info del curso
            return redirect()->route('showCourseInfo', ['id' => $courseId]);
        }


        // 4) En transacción: borrar progreso no‑examen e insertar nuevo progreso
        DB::transaction(function() use($userId, $next) {
            // a) Borrar todos los Progress de capítulos que NO son examen
            Progress::where('user_id', $userId)
                ->whereHas('exercise.chapter', fn($q) => $q->where('is_exam', false))
                ->delete();

            // b) Insertar registro 'incompleted' para cada ejercicio del capítulo siguiente
            $exercises = Exercise::where('chapter_id', $next->id)->get();
            foreach ($exercises as $ex) {
                Progress::create([
                    'user_id'     => $userId,
                    'exercise_id' => $ex->id,
                    'status'      => 'incompleted',
                ]);
            }
        });
        
        // 5) Redirigir según si es examen o no
        if ($next->is_exam) {
            return redirect()->route('course.chapter.exam', [
                'chapterId' => $next->id
            ]);
        }

        return redirect()->route('course.chapter.show', [
            'id' => $next->id
        ]);
    }

}
