<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Models\Evaluacion;
use App\Models\Estudiante;
use Illuminate\Http\Request;
use App\Models\EvaluacionEstudiante;
use App\Models\RespuestaEstudiante;
use App\Models\ResultadoEvaluacion;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class EvaluacionController extends Controller
{
    public function index(Request $request)
    {
        $term = $request->input('term');
        $cursoId = $request->input('curso_id');
        $usuario = $request->user();

        $query = Evaluacion::with([
            'docente',
            'curso',
            'lectura',
            'estudiantes.estudiante',
            'estudiantes.resultado',
        ]);

        if ($usuario->hasRole('docente')) {
            $query->where('docente_id', $usuario->id);
        } elseif ($usuario->hasRole('estudiante')) {
            $query->where('curso_id', optional($usuario->estudiante)->curso_id);
        }

        if ($cursoId) {
            $query->where('curso_id', $cursoId);
        }

        if ($term) {
            $query->where(function ($q) use ($term) {
                $q->where('titulo', 'LIKE', "%$term%")
                  ->orWhere('descripcion', 'LIKE', "%$term%");
            });
        }

        return response()->json($query->latest()->get(), 200);
    }

    public function show($id)
    {
        $evaluacion = Evaluacion::with([
            'docente',
            'curso.estudiantes',
            'lectura.preguntas.opciones',
            'estudiantes.estudiante',
            'estudiantes.respuestas.pregunta',
            'estudiantes.resultado',
        ])->find($id);

        if (!$evaluacion) {
            return response()->json(['message' => 'Evaluación no encontrada.'], 404);
        }

        return response()->json($evaluacion, 200);
    }

    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'docente_id' => 'required|exists:users,id',
            'curso_id' => 'required|exists:cursos,id',
            'lectura_id' => 'required|exists:lecturas,id',
            'titulo' => 'required|string|max:150',
            'descripcion' => 'nullable|string',
            'fecha_inicio' => 'nullable|date',
            'fecha_fin' => 'nullable|date|after_or_equal:fecha_inicio',
            'tiempo_limite' => 'nullable|integer|min:1',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Revise los datos ingresados.',
                'errors' => $validator->errors()
            ], 422);
        }

        $evaluacion = Evaluacion::create([
            'docente_id' => $request->docente_id,
            'curso_id' => $request->curso_id,
            'lectura_id' => $request->lectura_id,
            'titulo' => $request->titulo,
            'descripcion' => $request->descripcion,
            'fecha_inicio' => $request->fecha_inicio,
            'fecha_fin' => $request->fecha_fin,
            'tiempo_limite' => $request->tiempo_limite,
            'estado' => true,
        ]);

        return response()->json([
            'message' => 'Evaluación registrada correctamente.',
            'success' => true,
            'element' => $evaluacion->load(['docente', 'curso', 'lectura'])
        ], 201);
    }

    public function update(Request $request, $id)
    {
        $evaluacion = Evaluacion::find($id);

        if (!$evaluacion) {
            return response()->json(['message' => 'Evaluación no encontrada.'], 404);
        }

        $validator = Validator::make($request->all(), [
            'docente_id' => 'required|exists:users,id',
            'curso_id' => 'required|exists:cursos,id',
            'lectura_id' => 'required|exists:lecturas,id',
            'titulo' => 'required|string|max:150',
            'descripcion' => 'nullable|string',
            'fecha_inicio' => 'nullable|date',
            'fecha_fin' => 'nullable|date|after_or_equal:fecha_inicio',
            'tiempo_limite' => 'nullable|integer|min:1',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Revise los datos ingresados.',
                'errors' => $validator->errors()
            ], 422);
        }

        $evaluacion->update($request->only([
            'docente_id',
            'curso_id',
            'lectura_id',
            'titulo',
            'descripcion',
            'fecha_inicio',
            'fecha_fin',
            'tiempo_limite',
        ]));

        return response()->json([
            'message' => 'Evaluación actualizada correctamente.',
            'success' => true,
            'element' => $evaluacion->load(['docente', 'curso', 'lectura'])
        ], 200);
    }

    public function destroy($id)
    {
        $evaluacion = Evaluacion::find($id);

        if (!$evaluacion) {
            return response()->json(['message' => 'Evaluación no encontrada.'], 404);
        }

        $evaluacion->delete();

        return response()->json([
            'message' => 'Evaluación eliminada correctamente.',
            'success' => true
        ], 200);
    }

    public function iniciar(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'evaluacion_id' => 'required|exists:evaluaciones,id',
            'estudiante_id' => 'required|exists:estudiantes,id',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Revise los datos ingresados.',
                'errors' => $validator->errors()
            ], 422);
        }

        $evaluacion = Evaluacion::with([
            'lectura.preguntas' => function ($query) {
                $query->where('estado', true)->orderBy('orden');
            },
            'lectura.preguntas.opciones',
        ])->find($request->evaluacion_id);

        if (!$evaluacion->estado) {
            return response()->json([
                'message' => 'La evaluación no está habilitada.'
            ], 422);
        }

        $estudiante = Estudiante::find($request->estudiante_id);

        if ($estudiante->curso_id != $evaluacion->curso_id) {
            return response()->json([
                'message' => 'El estudiante no pertenece al curso de esta evaluación.'
            ], 422);
        }

        $erroresPerfil = $this->validarPerfilEstudiante($estudiante);

        if (!empty($erroresPerfil)) {
            return response()->json([
                'message' => 'Tu perfil de estudiante está incompleto o tiene datos inválidos. Pide a tu docente que lo actualice antes de rendir la evaluación.',
                'errors' => $erroresPerfil
            ], 422);
        }

        $evaluacionEstudiante = EvaluacionEstudiante::firstOrCreate(
            [
                'evaluacion_id' => $request->evaluacion_id,
                'estudiante_id' => $request->estudiante_id,
            ],
            [
                'fecha_inicio' => now(),
                'estado' => 'iniciado',
            ]
        );

        if ($evaluacionEstudiante->estado === 'finalizado') {
            return response()->json([
                'message' => 'El estudiante ya finalizó esta evaluación.',
                'element' => $evaluacionEstudiante->load('resultado')
            ], 422);
        }

        $evaluacion->lectura->preguntas->each(function ($pregunta) {
            $pregunta->opciones->each(function ($opcion) {
                $opcion->makeHidden('es_correcta');
            });
        });

        return response()->json([
            'message' => 'Evaluación iniciada correctamente.',
            'success' => true,
            'evaluacion_estudiante' => $evaluacionEstudiante,
            'evaluacion' => $evaluacion
        ], 200);
    }

    private function validarPerfilEstudiante(Estudiante $estudiante): array
    {
        $errores = [];

        if (is_null($estudiante->edad) || $estudiante->edad < 10 || $estudiante->edad > 25) {
            $errores[] = 'La edad del estudiante debe estar registrada entre 10 y 25 años.';
        }

        $genero = strtolower((string) $estudiante->genero);

        if (!in_array($genero, ['masculino', 'femenino'], true)) {
            $errores[] = 'El género del estudiante debe ser "masculino" o "femenino".';
        }

        $lenguaMaterna = strtolower((string) $estudiante->lengua_materna);

        if ($lenguaMaterna === 'aymara') {
            $lenguaMaterna = 'aimara';
        }

        if (!in_array($lenguaMaterna, ['castellano', 'aimara', 'quechua', 'otro'], true)) {
            $errores[] = 'La lengua materna del estudiante debe ser "castellano", "aimara", "quechua" u "otro".';
        }

        if (is_null($estudiante->frecuencia_lectura) || $estudiante->frecuencia_lectura < 0 || $estudiante->frecuencia_lectura > 7) {
            $errores[] = 'La frecuencia de lectura semanal del estudiante debe estar registrada entre 0 y 7.';
        }

        if (is_null($estudiante->tiempo_lectura_semanal) || $estudiante->tiempo_lectura_semanal < 0 || $estudiante->tiempo_lectura_semanal > 50) {
            $errores[] = 'El tiempo de lectura semanal del estudiante debe estar registrado entre 0 y 50 horas.';
        }

        return $errores;
    }

    public function finalizar(Request $request, $id)
    {
        $evaluacionEstudiante = EvaluacionEstudiante::with([
            'evaluacion.lectura.preguntas.opciones',
            'estudiante.curso'
        ])->find($id);

        if (!$evaluacionEstudiante) {
            return response()->json([
                'message' => 'Evaluación del estudiante no encontrada.'
            ], 404);
        }

        if ($evaluacionEstudiante->estado === 'finalizado') {
            return response()->json([
                'message' => 'Esta evaluación ya fue finalizada.',
                'element' => $evaluacionEstudiante->load(['respuestas', 'resultado'])
            ], 422);
        }

        $validator = Validator::make($request->all(), [
            'tiempo_lectura_segundos' => 'required|integer|min:1',
            'tiempo_respuesta_segundos' => 'required|integer|min:1',
            'respuestas' => 'required|array',
            'respuestas.*.pregunta_id' => 'required|exists:preguntas,id',
            'respuestas.*.opcion_id' => 'nullable|exists:opciones,id',
            'respuestas.*.respuesta_texto' => 'nullable|string',
            'respuestas.*.tiempo_respuesta_segundos' => 'nullable|integer|min:0',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Revise los datos ingresados.',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            DB::beginTransaction();

            $estudiante = $evaluacionEstudiante->estudiante;
            $preguntas = $evaluacionEstudiante->evaluacion->lectura->preguntas->where('estado', true);

            // El microservicio de IA solo sabe calificar preguntas de opción múltiple
            // (exige "opciones" con "es_correcta"). Las de formato "abierta" no se
            // envían a calificar: se guardan aparte, sin afectar el puntaje automático.
            $preguntasCalificables = $preguntas->where('formato', 'opcion_multiple');
            $preguntasAbiertas = $preguntas->where('formato', 'abierta');

            $cursoNivel = intval(optional($estudiante->curso)->nivel ?? optional($estudiante->curso)->nombre ?? 1);

            if ($cursoNivel < 1 || $cursoNivel > 6) {
                $cursoNivel = 1;
            }

            $lenguaMaterna = strtolower($estudiante->lengua_materna);

            if ($lenguaMaterna === 'aymara') {
                $lenguaMaterna = 'aimara';
            }

            $payload = [
                'edad' => $estudiante->edad,
                'curso' => $cursoNivel,
                'genero' => strtolower($estudiante->genero),
                'lengua_materna' => $lenguaMaterna,
                'frecuencia_lectura' => $estudiante->frecuencia_lectura,
                'tiempo_lectura_semanal' => floatval($estudiante->tiempo_lectura_semanal),
                'tiempo_lectura_segundos' => $request->tiempo_lectura_segundos,
                'tiempo_respuesta_segundos' => $request->tiempo_respuesta_segundos,
                'preguntas' => $preguntasCalificables->map(function ($pregunta) {
                    return [
                        'id' => $pregunta->id,
                        'tipo' => $pregunta->tipo,
                        'puntaje' => floatval($pregunta->puntaje),
                        'opciones' => $pregunta->opciones->map(function ($opcion) {
                            return [
                                'id' => $opcion->id,
                                'es_correcta' => (bool) $opcion->es_correcta,
                            ];
                        })->values()->toArray()
                    ];
                })->values()->toArray(),
                'respuestas' => $request->respuestas,
            ];

            $url = config('services.ia_comprension.url');

            $response = Http::timeout(20)->post($url, $payload);

            if (!$response->successful()) {
                DB::rollBack();

                return response()->json([
                    'message' => 'Error al procesar la evaluación con Python.',
                    'error' => $response->json()
                ], $response->status());
            }

            $resultadoPython = $response->json();
            $prediccion = $resultadoPython['prediccion'] ?? [];

            foreach ($resultadoPython['respuestas'] as $respuesta) {
                RespuestaEstudiante::create([
                    'evaluacion_estudiante_id' => $evaluacionEstudiante->id,
                    'pregunta_id' => $respuesta['pregunta_id'],
                    'opcion_id' => $respuesta['opcion_id'],
                    'es_correcta' => $respuesta['es_correcta'],
                    'puntaje_obtenido' => $respuesta['puntaje_obtenido'],
                    'tiempo_respuesta_segundos' => $respuesta['tiempo_respuesta_segundos'] ?? null,
                ]);
            }

            $respuestasRequest = collect($request->respuestas);

            foreach ($preguntasAbiertas as $pregunta) {
                $respuestaData = $respuestasRequest->firstWhere('pregunta_id', $pregunta->id);

                RespuestaEstudiante::create([
                    'evaluacion_estudiante_id' => $evaluacionEstudiante->id,
                    'pregunta_id' => $pregunta->id,
                    'opcion_id' => null,
                    'respuesta_texto' => $respuestaData['respuesta_texto'] ?? null,
                    'es_correcta' => false,
                    'puntaje_obtenido' => 0,
                    'tiempo_respuesta_segundos' => $respuestaData['tiempo_respuesta_segundos'] ?? null,
                ]);
            }

            $tiempoTotal = $request->tiempo_lectura_segundos + $request->tiempo_respuesta_segundos;

            $evaluacionEstudiante->update([
                'fecha_fin' => now(),
                'tiempo_lectura_segundos' => $request->tiempo_lectura_segundos,
                'tiempo_respuesta_segundos' => $request->tiempo_respuesta_segundos,
                'tiempo_total_segundos' => $tiempoTotal,
                'puntaje_literal' => $resultadoPython['puntaje_literal'],
                'puntaje_inferencial' => $resultadoPython['puntaje_inferencial'],
                'puntaje_critica' => $resultadoPython['puntaje_critica'],
                'puntaje_total' => $resultadoPython['puntaje_total'],
                'nivel_global' => $resultadoPython['nivel_global'],
                'estado' => 'finalizado',
            ]);

            ResultadoEvaluacion::create([
                'evaluacion_estudiante_id' => $evaluacionEstudiante->id,
                'cantidad_preguntas' => $resultadoPython['cantidad_preguntas'],
                'respuestas_correctas' => $resultadoPython['respuestas_correctas'],
                'respuestas_incorrectas' => $resultadoPython['respuestas_incorrectas'],
                'respuestas_omitidas' => $resultadoPython['respuestas_omitidas'],
                'porcentaje_aciertos' => $resultadoPython['puntaje_total'],

                'nivel_predicho' => $prediccion['nivel_predicho'] ?? null,
                'riesgo_lector' => $prediccion['riesgo_lector'] ?? null,

                'probabilidad_bajo' => $prediccion['probabilidad_bajo'] ?? 0,
                'probabilidad_medio' => $prediccion['probabilidad_medio'] ?? 0,
                'probabilidad_alto' => $prediccion['probabilidad_alto'] ?? 0,

                'area_fuerte' => $prediccion['area_fuerte'] ?? null,
                'area_debil' => $prediccion['area_debil'] ?? null,
                'recomendacion' => $prediccion['recomendacion'] ?? null,

                'modelo_usado' => $prediccion['modelo_usado'] ?? null,
                'modelo_version' => $prediccion['modelo_version'] ?? null,
                'respuesta_modelo' => $resultadoPython,
            ]);

            DB::commit();

            return response()->json([
                'message' => 'Evaluación finalizada correctamente.',
                'success' => true,
                'element' => $evaluacionEstudiante->load([
                    'evaluacion.lectura',
                    'estudiante',
                    'respuestas.pregunta',
                    'respuestas.opcion',
                    'resultado',
                ])
            ], 200);

        } catch (\Exception $th) {
            DB::rollBack();

            Log::error('Error al finalizar evaluación', [
                'error' => $th->getMessage()
            ]);

            return response()->json([
                'message' => 'No se pudo finalizar la evaluación.',
                'error' => $th->getMessage()
            ], 500);
        }
    }

    public function porEstudiante($id)
    {
        $data = EvaluacionEstudiante::with([
            'evaluacion.lectura',
            'evaluacion.curso',
            'resultado',
            'respuestas.pregunta',
            'respuestas.opcion',
        ])
        ->where('estudiante_id', $id)
        ->latest()
        ->get();

        return response()->json($data, 200);
    }

    public function porCurso($id)
    {
        $data = Evaluacion::with([
            'docente',
            'curso',
            'lectura',
            'estudiantes.estudiante',
            'estudiantes.resultado',
        ])
        ->where('curso_id', $id)
        ->latest()
        ->get();

        return response()->json($data, 200);
    }

    public function resultado($id)
    {
        $evaluacionEstudiante = EvaluacionEstudiante::with([
            'evaluacion.lectura',
            'estudiante.curso',
            'resultado',
            'respuestas.pregunta.opciones',
            'respuestas.opcion',
        ])->find($id);

        if (!$evaluacionEstudiante) {
            return response()->json([
                'message' => 'Evaluación del estudiante no encontrada.'
            ], 404);
        }

        return response()->json($evaluacionEstudiante, 200);
    }

    public function habilitar($id)
    {
        $evaluacion = Evaluacion::find($id);

        if (!$evaluacion) {
            return response()->json([
                'message' => 'Evaluación no encontrada.'
            ], 404);
        }

        $evaluacion->estado = !$evaluacion->estado;
        $evaluacion->save();

        return response()->json([
            'message' => 'Operación realizada correctamente.',
            'success' => true
        ], 200);
    }
}
