<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

class ParticipanteController extends Controller
{
    public function show($domain_id, $curso_id)
    {
        try {
            // ✅ Query base: Trae alumnos sin promedio
            $participantes = DB::table('alumnos as a')
                ->select(
                    'a.codigo',
                    'a.estadoAlumno',
                    'a.id',
                    'ca.id as curso_alumno_id',
                    DB::raw("CONCAT(a.nombres, ' ', a.apellidos) as nombres"),
                    'a.celular',
                    'a.email',
                    'a.dni',
                    'ca.curso_id',
                    'ca.estado_id',
                    'ca.estado_curso_id',
                    'ec.nombre as estado_alumno_curso',
                    'ec.color',
                    'ca.domain_id',
                    'ca.nota_recuperacion',
                    'ca.nota_final',
                    'ca.sistema_recuperacion',
                    'ca.criterio_nota_final'
                )
                ->join('curso_alumno as ca', function ($join) use ($curso_id, $domain_id) {
                    $join->on('ca.alumno_id', '=', 'a.id')
                        ->where('ca.curso_id', $curso_id)
                        ->where('ca.domain_id', $domain_id)
                        ->where('ca.estado_id', '!=', 0);
                })
                ->join('cursos as c', 'c.id', '=', 'ca.curso_id')
                ->join('estado_curso_alumno as ec', 'ec.id', '=', 'ca.estado_curso_id')
                ->where('a.domain_id', $domain_id)
                ->where('a.ciclo_id', '=', DB::raw('c.ciclo_id'))
                ->where('a.estadoAlumno', '!=', 'RETIRADO')
                ->orderBy('a.apellidos')
                ->get();

            // ✅ Calcular promedios en 1 sola query masiva
            $alumnosIds = $participantes->pluck('id')->toArray();

            if (!empty($alumnosIds)) {
                $promedios = $this->calcularPromediosMasivo($curso_id, $alumnosIds);

                // Asignar promedio a cada participante
                foreach ($participantes as $participante) {
                    $participante->promedio_general = $promedios[$participante->id] ?? 0;
                }
            }

            return response()->json($participantes, 200);
        } catch (\Exception $e) {
            Log::error('Error en ParticipanteController@show:', [
                'domain_id' => $domain_id,
                'curso_id' => $curso_id,
                'error' => $e->getMessage(),
                'line' => $e->getLine()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error al obtener participantes',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * ✅ Calcular promedios de todos los alumnos en 1 sola query
     * Palabra clave: CASE WHEN - Evalúa condiciones como un if-else en SQL
     */
    private function calcularPromediosMasivo($curso_id, $alumnosIds)
    {
        // Paso 1: Obtener promedio por grupo por alumno
        $promediosPorGrupo = DB::table('grupo_de_evaluaciones as ge')
            ->select(
                'ea.alumno_id',
                'ge.id as grupo_id',
                DB::raw('
                SUM(
                    CASE 
                        WHEN e.aplicar_en_calculo = 1 
                        THEN IFNULL(ea.nota, 0) * e.porcentaje_asignado 
                        ELSE 0 
                    END
                ) / NULLIF(
                    SUM(
                        CASE 
                            WHEN e.aplicar_en_calculo = 1 
                            THEN e.porcentaje_asignado 
                            ELSE 0 
                        END
                    ), 0
                ) as promedio_grupo
            ')
            )
            ->leftJoin('evaluaciones as e', function ($join) {
                $join->on('e.grupo_de_evaluaciones_id', '=', 'ge.id')
                    ->whereNull('e.deleted_at');
            })
            ->leftJoin('evaluaciones_alumno as ea', function ($join) use ($alumnosIds) {
                $join->on('ea.evaluacion_id', '=', 'e.id')
                    ->whereIn('ea.alumno_id', $alumnosIds);
            })
            ->where('ge.curso_id', $curso_id)
            ->whereNull('ge.deleted_at')
            ->groupBy('ea.alumno_id', 'ge.id')
            ->havingRaw('SUM(
            CASE 
                WHEN e.aplicar_en_calculo = 1 
                THEN e.porcentaje_asignado 
                ELSE 0 
            END
        ) > 0')
            ->get();

        // Paso 2: Agrupar por alumno y calcular promedio general
        $promediosFinales = [];

        foreach ($promediosPorGrupo->groupBy('alumno_id') as $alumnoId => $grupos) {
            // Filtrar grupos que tienen promedio válido
            $gruposValidos = $grupos->filter(function ($grupo) {
                return $grupo->promedio_grupo !== null && $grupo->promedio_grupo > 0;
            });

            if ($gruposValidos->count() > 0) {
                $suma = $gruposValidos->sum('promedio_grupo');
                $promediosFinales[$alumnoId] = round($suma / $gruposValidos->count(), 2);
            } else {
                $promediosFinales[$alumnoId] = 0;
            }
        }

        // Paso 3: Asegurar que todos los alumnos tengan un promedio (aunque sea 0)
        foreach ($alumnosIds as $alumnoId) {
            if (!isset($promediosFinales[$alumnoId])) {
                $promediosFinales[$alumnoId] = 0;
            }
        }

        return $promediosFinales;
    }

    /**
     * ✅ Guardar nota de recuperación y calcular nota final
     */
    public function guardarRecuperacion(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'curso_alumno_id' => 'required|integer|exists:curso_alumno,id',
                'nota_recuperacion' => 'required|numeric|min:0|max:20',
                'sistema_recuperacion' => 'required|in:10_11_12,menor_12',
                'criterio_nota_final' => 'required|in:nota_mas_alta,nota_recuperacion',
                'promedio_general' => 'required|numeric|min:0|max:20'
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'errors' => $validator->errors()
                ], 422);
            }

            $cursoAlumnoId = $request->input('curso_alumno_id');
            $notaRecuperacion = (float) $request->input('nota_recuperacion');
            $sistemaRecuperacion = $request->input('sistema_recuperacion');
            $criterioNotaFinal = $request->input('criterio_nota_final');
            $promedioGeneral = (float) $request->input('promedio_general');

            DB::beginTransaction();

            // Calcular nota final
            $notaFinal = $this->calcularNotaFinal(
                $promedioGeneral,
                $notaRecuperacion,
                $criterioNotaFinal
            );

            // Determinar estado
            $nuevoEstadoCursoId = $this->determinarEstado(
                $promedioGeneral,
                $notaRecuperacion,
                $notaFinal,
                $sistemaRecuperacion
            );

            // Actualizar BD
            DB::table('curso_alumno')
                ->where('id', $cursoAlumnoId)
                ->update([
                    'nota_recuperacion' => $notaRecuperacion,
                    'nota_final' => $notaFinal,
                    'sistema_recuperacion' => $sistemaRecuperacion,
                    'criterio_nota_final' => $criterioNotaFinal,
                    'estado_curso_id' => $nuevoEstadoCursoId,
                    'estado_id' => ($nuevoEstadoCursoId == 3 || $nuevoEstadoCursoId == 4) ? 6 : 2,
                    'updated_at' => Carbon::now()
                ]);

            // ✅ OBTENER nombre y color del estado
            $estadoInfo = DB::table('estado_curso_alumno')
                ->where('id', $nuevoEstadoCursoId)
                ->first();

            DB::commit();

            // ✅ Log para debug
            Log::info('Recuperación guardada:', [
                'curso_alumno_id' => $cursoAlumnoId,
                'promedio_general' => $promedioGeneral,
                'nota_recuperacion' => $notaRecuperacion,
                'nota_final' => $notaFinal,
                'criterio' => $criterioNotaFinal,
                'sistema' => $sistemaRecuperacion,
                'estado_curso_id' => $nuevoEstadoCursoId,
                'estado_nombre' => $estadoInfo->nombre ?? 'DESCONOCIDO'
            ]);

            return response()->json([
                'success' => true,
                'message' => 'Nota de recuperación guardada correctamente',
                'data' => [
                    'nota_recuperacion' => $notaRecuperacion,
                    'nota_final' => $notaFinal,
                    'estado_curso_id' => $nuevoEstadoCursoId,
                    'estado_nombre' => $estadoInfo->nombre ?? 'DESCONOCIDO',     // ✅ AGREGADO
                    'estado_color' => $estadoInfo->color ?? '#9CA3AF'            // ✅ AGREGADO
                ]
            ], 200);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Error guardando recuperación:', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error al guardar la recuperación',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Calcular nota final según criterio
     */
    private function calcularNotaFinal($promedio, $notaRecuperacion, $criterio)
    {
        if ($criterio === 'nota_mas_alta') {
            return max($promedio, $notaRecuperacion);
        }
        return $notaRecuperacion;
    }

    /**
     * ✅ NUEVO: Aplicar sistema de recuperación a TODOS los alumnos del curso
     * Endpoint: POST /api/participantes/aplicar-sistema
     */
    public function aplicarSistemaRecuperacion(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'curso_id' => 'required|integer',
                'domain_id' => 'required|integer',
                'sistema_recuperacion' => 'required|in:10_11_12,menor_12'
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'errors' => $validator->errors()
                ], 422);
            }

            $cursoId = $request->input('curso_id');
            $domainId = $request->input('domain_id');
            $sistema = $request->input('sistema_recuperacion');

            DB::beginTransaction();

            // Obtener todos los alumnos del curso con sus promedios
            $alumnos = DB::table('alumnos as a')
                ->select(
                    'a.id as alumno_id',
                    'ca.id as curso_alumno_id'
                )
                ->join('curso_alumno as ca', function ($join) use ($cursoId, $domainId) {
                    $join->on('ca.alumno_id', '=', 'a.id')
                        ->where('ca.curso_id', $cursoId)
                        ->where('ca.domain_id', $domainId)
                        ->whereIn('ca.estado_id', [2, 6]);
                })
                ->where('a.domain_id', $domainId)
                ->where('a.estadoAlumno', '!=', 'RETIRADO')
                ->get();

            $actualizados = 0;
            $alumnosIds = $alumnos->pluck('alumno_id')->toArray();

            // Calcular promedios
            $promedios = $this->calcularPromediosMasivo($cursoId, $alumnosIds);

            foreach ($alumnos as $alumno) {
                $promedio = $promedios[$alumno->alumno_id] ?? 0;

                // ✅ APLICAR REGLAS AUTOMÁTICAS
                $nuevoEstado = $this->determinarEstadoAutomatico($promedio, $sistema);

                // Solo actualizar si hay cambio de estado
                if ($nuevoEstado !== null) {
                    DB::table('curso_alumno')
                        ->where('id', $alumno->curso_alumno_id)
                        ->update([
                            'sistema_recuperacion' => $sistema,
                            'estado_curso_id' => $nuevoEstado,
                            'estado_id' => ($nuevoEstado == 3 || $nuevoEstado == 4) ? 6 : 2,
                            'updated_at' => Carbon::now()
                        ]);

                    $actualizados++;
                }
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => "Sistema aplicado correctamente",
                'data' => [
                    'total_alumnos' => count($alumnos),
                    'actualizados' => $actualizados,
                    'sistema' => $sistema
                ]
            ], 200);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Error aplicando sistema:', [
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error al aplicar el sistema',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * ✅ NUEVO: Determinar estado automático según promedio y sistema
     * (sin nota de recuperación)
     */
    private function determinarEstadoAutomatico($promedio, $sistema)
    {
        if ($sistema === '10_11_12') {
            if ($promedio > 12.5) {
                return 3; // APROBADO automático
            }
            if ($promedio < 9.4) {
                return 4; // DESAPROBADO automático
            }
            // Entre 9.5 y 12.4: mantener EN PROCESO (necesita recuperación)
            return 2;
        }

        if ($sistema === 'menor_12') {
            if ($promedio >= 12.4) {
                return 3; // APROBADO automático
            }
            // Menor a 12.4: mantener EN PROCESO (necesita recuperación)
            return 2;
        }

        return null; // No cambiar estado
    }

    /**
     * ✅ CORREGIDO: Determinar estado según sistema y NOTA FINAL (no promedio)
     */
    private function determinarEstado($promedio, $notaRecuperacion, $notaFinal, $sistema)
    {
        if ($sistema === '10_11_12') {
            if ($notaFinal >= 10.5) {
                return 3; // APROBADO
            } else {
                return 4; // DESAPROBADO
            }
        }

        if ($sistema === 'menor_12') {
            if ($notaRecuperacion !== null) {
                if ($notaRecuperacion >= 12.5) {
                    return 3; // APROBADO
                } else {
                    return 4; // DESAPROBADO
                }
            }

            if ($promedio >= 12.4) {
                return 3; // APROBADO automático
            }

            return 2; // EN PROCESO
        }

        return 2;
    }

    public function store(Request $request)
    {
        $domainId = $request->input('domain_id');
        $cursoId = $request->input('curso_id');
        $alumnoId = $request->input('alumno_id');
        //verificar si el alumno ya esta registrado en el curso
        $cursoAlumno = DB::table('curso_alumno')
            ->where('curso_id', $cursoId)
            ->where('alumno_id', $alumnoId)
            ->where('domain_id', $domainId)
            ->first();
        if ($cursoAlumno) {
            //remover el registro
            DB::table('curso_alumno')->where('id', $cursoAlumno->id)->delete();
        } else {
            //insertar el registro
            DB::table('curso_alumno')->insert([
                'curso_id' => $cursoId,
                'alumno_id' => $alumnoId,
                'domain_id' => $domainId
            ]);
        }
    }
    public function getPromedioEvaluaciones($curso_id, $alumno_id)
    {
        try {
            // ✅ CORREGIDO: Promedio ponderado por indicador considerando porcentaje_asignado
            $promedioGeneral = DB::table(DB::raw('(
                SELECT 
                    ge.id AS grupo_id,
                    ge.nombre_del_grupo,
                    -- ✅ Promedio PONDERADO por porcentaje_asignado (solo evaluaciones marcadas)
                    SUM(
                        CASE 
                            WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                            THEN IFNULL(ea.nota, 0) * e.porcentaje_asignado 
                            ELSE 0 
                        END
                    ) / 
                    NULLIF(
                        SUM(
                            CASE 
                                WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                                THEN e.porcentaje_asignado 
                                ELSE 0 
                            END
                        ), 0
                    ) AS promedio_notas_por_grupo,
                    SUM(e.porcentaje_asignado) AS total_porcentaje
                FROM grupo_de_evaluaciones ge
                LEFT JOIN evaluaciones e ON e.grupo_de_evaluaciones_id = ge.id
                LEFT JOIN evaluaciones_alumno ea ON ea.evaluacion_id = e.id AND ea.alumno_id = ?
                WHERE ge.curso_id = ?
                GROUP BY ge.id, ge.nombre_del_grupo
                HAVING SUM(
                    CASE 
                        WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                        THEN e.porcentaje_asignado 
                        ELSE 0 
                    END
                ) > 0
            ) AS subquery'))
                ->select(DB::raw('AVG(subquery.promedio_notas_por_grupo) AS promedio_general'))
                ->setBindings([$alumno_id, $curso_id])
                ->first();

            return response()->json([
                'success' => true,
                'curso_id' => $curso_id,
                'alumno_id' => $alumno_id,
                'promedio_general' => $promedioGeneral ? round($promedioGeneral->promedio_general, 2) : 0
            ]);
        } catch (\Exception $e) {
            Log::error('Error calculando promedio:', [
                'curso_id' => $curso_id,
                'alumno_id' => $alumno_id,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error al calcular el promedio',
                'promedio_general' => 0
            ], 500);
        }
    }


    public function getPromedioCurso($curso_id)
    {
        try {
            // Obtener los IDs de los alumnos inscritos en el curso
            $alumnos = DB::table('curso_alumno')
                ->where('curso_id', $curso_id)
                ->pluck('alumno_id');

            // Inicializar la suma de los promedios
            $sumaPromedios = 0;
            $alumnosConPromedio = 0;

            // Recorrer cada alumno y calcular su promedio ponderado
            foreach ($alumnos as $alumno_id) {
                $promedioAlumno = DB::table(DB::raw('(
                    SELECT 
                        ge.id AS grupo_id,
                        -- ✅ Promedio PONDERADO por porcentaje_asignado (solo evaluaciones marcadas)
                        SUM(
                            CASE 
                                WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                                THEN IFNULL(ea.nota, 0) * e.porcentaje_asignado 
                                ELSE 0 
                            END
                        ) / 
                        NULLIF(
                            SUM(
                                CASE 
                                    WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                                    THEN e.porcentaje_asignado 
                                    ELSE 0 
                                END
                            ), 0
                        ) AS promedio_notas_por_grupo
                    FROM grupo_de_evaluaciones ge
                    LEFT JOIN evaluaciones e ON e.grupo_de_evaluaciones_id = ge.id
                    LEFT JOIN evaluaciones_alumno ea ON ea.evaluacion_id = e.id AND ea.alumno_id = ?
                    WHERE ge.curso_id = ?
                    GROUP BY ge.id
                    HAVING SUM(
                        CASE 
                            WHEN IFNULL(e.aplicar_en_calculo, 1) = 1 
                            THEN e.porcentaje_asignado 
                            ELSE 0 
                        END
                    ) > 0
                ) AS subquery'))
                    ->select(DB::raw('AVG(subquery.promedio_notas_por_grupo) AS promedio_general'))
                    ->setBindings([$alumno_id, $curso_id])
                    ->first();

                // Sumar el promedio del alumno al total solo si tiene evaluaciones
                if ($promedioAlumno && $promedioAlumno->promedio_general !== null) {
                    $sumaPromedios += $promedioAlumno->promedio_general;
                    $alumnosConPromedio++;
                }
            }

            // Calcular el promedio general del curso
            $promedioGeneralCurso = $alumnosConPromedio > 0 ? $sumaPromedios / $alumnosConPromedio : 0;

            // Devolver el resultado en formato JSON
            return response()->json([
                'success' => true,
                'curso_id' => $curso_id,
                'promedio_general' => round($promedioGeneralCurso, 2),
                'total_alumnos' => count($alumnos),
                'alumnos_con_promedio' => $alumnosConPromedio
            ]);
        } catch (\Exception $e) {
            Log::error('Error calculando promedio del curso:', [
                'curso_id' => $curso_id,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Error al calcular el promedio del curso',
                'promedio_general' => 0
            ], 500);
        }
    }

    public function updateEstadoCursoAlumno(Request $request)
    {
        $domainId   = $request->input('domain_id');
        $alumnoId   = $request->input('id_alumno');
        $cursoId    = $request->input('curso_id');
        $estadoId   = $request->input('id_estado');

        // Determinar el estado_id basado en el estado_curso_id
        $estadoAdministrativo = 1; // Por defecto PENDIENTE

        // Obtener el nombre del estado para determinar el estado administrativo
        $estadoCurso = DB::table('estado_curso_alumno')
            ->where('id', $estadoId)
            ->first();

        if ($estadoCurso) {
            switch ($estadoCurso->nombre) {
                case 'PENDIENTE':
                    $estadoAdministrativo = 1; // PENDIENTE
                    break;
                case 'EN PROCESO':
                    $estadoAdministrativo = 2; // EN PROCESO
                    break;
                case 'APROBADO':
                case 'DESAPROBADO':
                    $estadoAdministrativo = 6; // FINALIZADO
                    break;
                default:
                    $estadoAdministrativo = 1; // PENDIENTE por defecto
                    break;
            }
        }

        DB::table('curso_alumno')
            ->where('alumno_id', $alumnoId)
            ->where('curso_id', $cursoId)
            ->where('domain_id', $domainId)
            ->update([
                'estado_curso_id' => $estadoId,
                'estado_id' => $estadoAdministrativo, // 🔧 AGREGAR: estado_id = 6 cuando sea APROBADO/DESAPROBADO
                'updated_at' => Carbon::now()
            ]);

        return response()->json([
            'message' => 'Estado actualizado correctamente.',
            'estado_administrativo' => $estadoAdministrativo,
            'estado_curso' => $estadoCurso->nombre ?? 'DESCONOCIDO'
        ], 201);
    }
}
