<?php

namespace App\Http\Controllers;
use App\Models\Postulante;
use App\Models\Proceso;
use App\Models\Area;
use App\Models\Curso;
use App\Models\Pregunta;
use App\Models\Alternativa;
use App\Models\Examen;
use App\Models\PreguntaAsignada;
use App\Models\AlternativaAsignada;
use App\Models\DetalleResultado;
use App\Models\RespuestaPostulante;
use App\Models\ResultadoExamen;
use App\Models\Recomendaciones;
use App\Models\Pago;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Http;
use App\Services\ExamenService;
use Illuminate\Support\Facades\DB;

class ExamenController extends Controller
{

    protected $examenService;

    public function __construct(ExamenService $examenService)
    {
        $this->examenService = $examenService;
    }
public function procesoexamen(Request $request)
{
    $postulante = $request->user();

    $procesos = Proceso::where('activo', 1)
        ->whereNotExists(function ($q) use ($postulante) {
            $q->select(\DB::raw(1))
              ->from('examenes')
              ->join('area_proceso', 'area_proceso.id', '=', 'examenes.area_proceso_id')
              ->whereColumn('area_proceso.proceso_id', 'procesos.id')
              ->where('examenes.postulante_id', $postulante->id);
        })
        ->select('id', 'nombre', 'requiere_pago')
        ->get();

    return response()->json($procesos);
}

    
public function areas(Request $request)
{
    $procesoId = $request->query('proceso_id');

    $areas = Area::select('areas.id', 'areas.nombre')
        ->whereHas('procesos', function ($query) use ($procesoId) {
            $query->where('procesos.id', $procesoId)
                  ->where('procesos.activo', 1);
        })
        ->with(['procesos' => function ($q) use ($procesoId) {
            $q->where('procesos.id', $procesoId)
              ->select('procesos.id')
              ->withPivot('id', 'proceso_id', 'area_id');
        }])
        ->get()
        ->map(function ($area) {
            $pivot = $area->procesos->first()->pivot;

            return [
                'area_id'          => $area->id,
                'nombre'           => $area->nombre,
                'area_proceso_id'  => $pivot->id, 
            ];
        });

    return response()->json($areas);
}


    
public function crearExamen(Request $request)
{
    $postulante = $request->user();

    $request->validate([
        'area_proceso_id' => 'required|exists:area_proceso,id',
    ]);

    // 🔥 Obtener TODO desde el pivot
    $areaProceso = \DB::table('area_proceso')
        ->join('procesos', 'procesos.id', '=', 'area_proceso.proceso_id')
        ->join('areas', 'areas.id', '=', 'area_proceso.area_id')
        ->where('area_proceso.id', $request->area_proceso_id)
        ->select(
            'area_proceso.id',
            'area_proceso.area_id',
            'area_proceso.proceso_id',
            'procesos.requiere_pago'
        )
        ->first();

    if (!$areaProceso) {
        return response()->json(['message' => 'Relación área-proceso inválida'], 400);
    }

    $yaDioProceso = Examen::join('area_proceso', 'area_proceso.id', '=', 'examenes.area_proceso_id')
    ->where('examenes.postulante_id', $postulante->id)
    ->where('area_proceso.proceso_id', $areaProceso->proceso_id)
    ->exists();

    if ($yaDioProceso) {
        return response()->json([
            'message' => 'Ya rendiste un examen para este proceso'
        ], 400);
    }

    $pagado = 0;
    $pagoId = null;

    // 💰 Validación de pago
    if ($areaProceso->requiere_pago) {
        $request->validate([
            'tipo_pago'   => 'required|in:pyto_peru,banco_nacion,caja',
            'codigo_pago' => 'required',
        ]);

        $response = $this->validarPago(
            $request->tipo_pago,
            $request->codigo_pago,
            $postulante->dni
        );

        if (!$response['estado']) {
            return response()->json(['message' => 'Pago inválido'], 400);
        }

        $pago = Pago::firstOrCreate(
            [
                'codigo_pago' => $request->codigo_pago,
                'tipo_pago' => $request->tipo_pago,
            ],
            [
                'postulante_id' => $postulante->id,
                'monto' => $response['monto'],
                'fecha_pago' => $response['fecha_pago'],
            ]
        );

        if ($pago->utilizado) {
            return response()->json(['message' => 'Pago ya utilizado'], 400);
        }

        $pago->update(['utilizado' => true]);

        $pagado = 1;
        $pagoId = $pago->id;
    }

    // 🧠 Crear / actualizar examen
    $examen = Examen::updateOrCreate(
        ['postulante_id' => $postulante->id,
        'area_proceso_id' => $areaProceso->id, // 🔥 pivot
        'pagado' => $pagado,
        'tipo_pago' => $request->tipo_pago ?? null,
        'pago_id' => $pagoId,
        ]
    );

    return response()->json([
        'success' => true,
        'examen_id' => $examen->id,
        'mensaje' => 'Examen creado correctamente',
    ]);
}


    public function validarPago($tipoPago, $codigoPago, $dni)
    {
        return match ($tipoPago) {
            'pyto_peru'     => $this->validarPagoPytoPeru($codigoPago, $dni),
            'banco_nacion'  => $this->validarPagoBancoNacion($codigoPago, $dni),
            'caja'          => $this->validarPagoCaja($codigoPago, $dni),
            default         => ['estado' => false],
        };
    }

    private function validarPagoBancoNacion($secuencia, $dni)
    {
        $url = 'https://inscripciones.admision.unap.edu.pe/api/get-pagos-banco-secuencia';

        $response = Http::post($url, [
            'secuencia' => $secuencia,
        ]);
        
        if (!$response->successful()) {
            \Log::error('Error en la solicitud a la API', ['status' => $response->status(), 'body' => $response->body()]);
            return ['estado' => false, 'message' => 'Error en la solicitud a la API'];
        }
        
        $data = $response->json();
        
        if (isset($data['estado']) && $data['estado'] === true) {
            foreach ($data['datos'] as $pago) {
                if (isset($pago['dni']) && trim($pago['dni']) == trim($dni)) {
                    return [
                        'estado' => true,
                        'monto' => $pago['imp_pag'],
                        'fecha_pago' => $pago['fch_pag'],
                    ];
                }
            }
        }
        
        return ['estado' => false, 'message' => 'Datos no válidos o no encontrados'];
    }
 
    private function validarPagoPytoPeru($authorizationCode, $dni)
    {
        $url = "https://service2.unap.edu.pe/PAYMENTS_MNG/v1/{$dni}/8/";
        $response = Http::get($url);
    
        if ($response->successful()) {
            $data = $response->json();
            
            
            if (isset($data['data'][0]['autorizationCode']) && $data['data'][0]['autorizationCode'] === $authorizationCode) {
                return [
                    'estado' => true,
                    'monto' => $data['data'][0]['total'], 
                    'fecha_pago' => $data['data'][0]['confirmedDate'], 
                ];
            }
        }
    
        return ['estado' => false, 'message' => 'El código de autorización no coincide.'];
    }

    private function validarPagoCaja($codigoPago, $dni)
    {
        $url = "https://inscripciones.admision.unap.edu.pe/api/get-pago-caja/{$dni}/{$codigoPago}";

        $response = Http::get($url);

        if (!$response->successful()) {
            \Log::error('Error API Caja', [
                'status' => $response->status(),
                'body' => $response->body()
            ]);
            return ['estado' => false, 'message' => 'Error en la API de Caja'];
        }

        $data = $response->json();

        if (
            isset($data['paymentTitle'], $data['paymentAmount'], $data['paymentDatetime']) &&
            trim($data['paymentTitle']) === trim($codigoPago)
        ) {
            return [
                'estado' => true,
                'monto' => (float) $data['paymentAmount'],
                'fecha_pago' => $data['paymentDatetime'],
            ];
        }

        return ['estado' => false, 'message' => 'Pago no válido o no encontrado'];
    }
    
public function miExamenActual(Request $request)
{
    $postulante = $request->user();


    $examen = Examen::join('area_proceso', 'area_proceso.id', '=', 'examenes.area_proceso_id')
        ->join('areas', 'areas.id', '=', 'area_proceso.area_id')
        ->join('procesos', 'procesos.id', '=', 'area_proceso.proceso_id')
        ->where('examenes.postulante_id', $postulante->id)
        ->select(
            'examenes.id',
            'examenes.pagado',
            'examenes.tipo_pago',
            'examenes.intentos',                    
            'areas.id as area_id',
            'areas.nombre as area_nombre',
            'procesos.id as proceso_id',
            'procesos.nombre as proceso_nombre',
            'procesos.intentos_maximos as proceso_intentos_maximos'
        )
        ->latest('examenes.created_at') 
        ->first();

    if (!$examen) {
        return response()->json([
            'success' => true,
            'mensaje' => 'No tienes exámenes asignados actualmente',
            'examen' => null
        ]);
    }

    return response()->json([
        'success' => true,
        'examen' => [
            'id' => $examen->id,
            'intentos' => $examen->intentos,
            'intentos_maximos' => $examen->proceso_intentos_maximos,
            'proceso' => [
                'id' => $examen->proceso_id,
                'nombre' => $examen->proceso_nombre,
            ],
            'area' => [
                'id' => $examen->area_id,
                'nombre' => $examen->area_nombre,
            ],
            'pagado' => $examen->pagado,
            'tipo_pago' => $examen->tipo_pago ?? null,
        ]
    ]);
}



    

public function generarPreguntas($examenId)
{
    $examen = Examen::findOrFail($examenId);

    $postulante = request()->user();
    if ($examen->postulante_id !== $postulante->id) {
        return response()->json([
            'success' => false,
            'message' => 'No autorizado'
        ], 403);
    }

    if ($examen->preguntasAsignadas()->exists()) {
        return response()->json([
            'success' => true,
            'message' => 'El examen ya tiene preguntas generadas',
            'ya_tiene_preguntas' => true,
            'total_preguntas' => $examen->preguntasAsignadas()->count()
        ]);
    }

    $resultado = $this->examenService->generarPreguntasExamen($examen);

    if (!$resultado['success']) {
        return response()->json($resultado, 400);
    }

    return response()->json([
        'success' => true,
        'message' => 'Preguntas generadas exitosamente',
        'ya_tiene_preguntas' => false,
        'total_preguntas' => $examen->preguntasAsignadas()->count()
    ]);
}


public function iniciarExamen(Request $request)
{
    $request->validate([
        'examen_id' => 'required|exists:examenes,id'
    ]);

    $examen = Examen::findOrFail($request->examen_id);

    $postulante = $request->user();
    if ($examen->postulante_id !== $postulante->id) {
        return response()->json([
            'success' => false,
            'message' => 'No autorizado'
        ], 403);
    }

    $areaProceso = \DB::table('area_proceso')
        ->join('procesos', 'area_proceso.proceso_id', '=', 'procesos.id')
        ->join('areas', 'area_proceso.area_id', '=', 'areas.id')
        ->where('area_proceso.id', $examen->area_proceso_id)
        ->select(
            'procesos.id as proceso_id',
            'procesos.nombre as proceso_nombre',
            'procesos.duracion as proceso_duracion',
            'procesos.intentos_maximos as proceso_intentos_maximos',
            'areas.nombre as area_nombre'
        )
        ->first();

    if (!$examen->preguntasAsignadas()->exists()) {
        return response()->json([
            'success' => false,
            'message' => 'El examen no tiene preguntas generadas'
        ], 400);
    }

    if ($areaProceso && $examen->intentos >= $areaProceso->proceso_intentos_maximos) {
        return response()->json([
            'success' => false,
            'message' => 'Has alcanzado el número máximo de intentos para este proceso'
        ], 403);
    }

    $examen->increment('intentos');

    $examen->update([
        'hora_inicio' => now(), 
        'estado' => 'en_progreso'
    ]);

    $preguntas = $this->examenService->obtenerPreguntasExamen($examen);

    return response()->json([
        'success' => true,
        'examen' => [
            'id' => $examen->id,
            'estado' => $examen->estado,
            'hora_inicio' => $examen->hora_inicio,
            'intentos' => $examen->intentos,
            'intentos_maximos' => $areaProceso->proceso_intentos_maximos ?? null,
            'proceso' => $areaProceso->proceso_nombre ?? null,
            'duracion' => $areaProceso->proceso_duracion ?? null,
            'area' => $areaProceso->area_nombre ?? null
        ],
        'preguntas' => $preguntas
    ]);
}



    public function responderPregunta($preguntaAsignadaId, Request $request)
    {
        $request->validate([
            'respuesta' => 'nullable|string'
        ]);

        $preguntaAsignada = PreguntaAsignada::with(['examen', 'pregunta'])
            ->findOrFail($preguntaAsignadaId);

        $postulante = $request->user();
        if ($preguntaAsignada->examen->postulante_id !== $postulante->id) {
            return response()->json([
                'success' => false,
                'message' => 'No autorizado'
            ], 403);
        }

        $resultado = $this->examenService->guardarRespuesta(
            $preguntaAsignada,
            $request->respuesta
        );

        return response()->json($resultado);
    }



    public function finalizarExamen($examenId)
    {
        $examen = Examen::findOrFail($examenId);

        $postulante = request()->user();

        // Validar que el examen le pertenezca al postulante autenticado
        if ((int) $examen->postulante_id !== (int) $postulante->id) {
            return response()->json([
                'success' => false,
                'message' => 'No autorizado'
            ], 403);
        }

        // (Opcional) Evitar finalizar 2 veces
        if ($examen->estado === 'finalizado') {
            return response()->json([
                'success' => false,
                'message' => 'El examen ya está finalizado'
            ], 409);
        }

        // Finalizar examen
        $examen->update([
            'estado'   => 'finalizado',
            'hora_fin' => now(),
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Examen finalizado exitosamente'
        ]);
    }



    public function calificarExamen($examenId, Request $request)
    {
        $postulante = $request->user();
        if (!$postulante) {
            return response()->json(['success' => false, 'mensaje' => 'No autenticado.'], 401);
        }

        return DB::transaction(function () use ($examenId, $postulante) {

            // 1) Validar examen del postulante
            $examen = DB::table('examenes')
                ->where('id', $examenId)
                ->where('postulante_id', $postulante->id)
                ->first();

            if (!$examen) {
                return response()->json([
                    'success' => false,
                    'mensaje' => 'No se encontró un examen para este postulante.'
                ], 404);
            }

            // 2) Si ya está calificado, devolver existente (y opcionalmente recalcular orden)
            $existente = DB::table('resultados_examenes')
                ->where('examen_id', $examen->id)
                ->first();

            if ($existente) {
                // Obtener proceso_id para poder recalcular si deseas (opcional)
                $procesoId = DB::table('area_proceso')
                    ->where('id', $examen->area_proceso_id)
                    ->value('proceso_id');

               
                if ($procesoId) $this->recalcularOrdenMerito($procesoId);

                return response()->json([
                    'success' => true,
                    'mensaje' => 'Examen ya calificado.',
                    'total_puntos' => (float)$existente->total_puntos,
                    'total_correctas' => (int)$existente->total_correctas,
                    'total_incorrectas' => (int)$existente->total_incorrectas,
                    'total_nulas' => (int)$existente->total_nulas,
                    'porcentaje_correctas' => (float)$existente->porcentaje_correctas,
                    'calificacion_sobre_20' => (float)$existente->calificacion_sobre_20,
                    'orden_merito' => $existente->orden_merito,
                    'correctas_por_curso' => json_decode($existente->correctas_por_curso, true),
                    'incorrectas_por_curso' => json_decode($existente->incorrectas_por_curso ?? '[]', true),
                    'preguntas_totales_por_curso' => json_decode($existente->preguntas_totales_por_curso ?? '[]', true),
                ]);
            }

            // 3) Obtener configuración de calificación desde proceso -> calificaciones
            $cfg = DB::table('area_proceso as ap')
                ->join('procesos as pr', 'pr.id', '=', 'ap.proceso_id')
                ->join('calificaciones as ca', 'ca.id', '=', 'pr.calificacion_id')
                ->where('ap.id', $examen->area_proceso_id)
                ->select(
                    'pr.id as proceso_id',
                    'ca.puntos_correcta',
                    'ca.puntos_incorrecta',
                    'ca.puntos_nula',
                    'ca.puntaje_maximo'
                )
                ->first();

            if (!$cfg) {
                return response()->json([
                    'success' => false,
                    'mensaje' => 'No se ha definido un tipo de calificación para este proceso.'
                ], 400);
            }

            $puntosCorrecta   = (float) $cfg->puntos_correcta;
            $puntosIncorrecta = (float) $cfg->puntos_incorrecta;
            $puntosNula       = (float) $cfg->puntos_nula;
            $puntajeMaximo    = (float) $cfg->puntaje_maximo;

            // 4) Traer preguntas asignadas con su pregunta y curso
            $items = DB::table('preguntas_asignadas as pa')
                ->join('preguntas as p', 'p.id', '=', 'pa.pregunta_id')
                ->join('cursos as c', 'c.id', '=', 'p.curso_id')
                ->where('pa.examen_id', $examen->id)
                ->select(
                    'pa.id as pa_id',
                    'pa.estado as pa_estado',
                    'pa.respuesta_usuario',
                    'p.respuesta_correcta',
                    'c.nombre as curso_nombre'
                )
                ->get();

            if ($items->isEmpty()) {
                return response()->json([
                    'success' => false,
                    'mensaje' => 'El examen no tiene preguntas asignadas.'
                ], 422);
            }

            // 5) Calificar y actualizar cada pregunta_asignada
            $totalPuntos = 0.0;
            $totalCorrectas = 0;
            $totalIncorrectas = 0;
            $totalNulas = 0;

            $correctasPorCurso = [];
            $incorrectasPorCurso = [];
            $preguntasTotalesPorCurso = [];

            foreach ($items as $row) {
                $curso = $row->curso_nombre;

                $preguntasTotalesPorCurso[$curso] = ($preguntasTotalesPorCurso[$curso] ?? 0) + 1;
                $correctasPorCurso[$curso] = $correctasPorCurso[$curso] ?? 0;
                $incorrectasPorCurso[$curso] = $incorrectasPorCurso[$curso] ?? 0;

                $nuevoEsCorrecta = 2;          // 2 = blanco
                $nuevoPuntaje    = $puntosNula; // nula/blanco

                if ($row->pa_estado === 'anulada') {
                    // anulada => nula
                    $nuevoEsCorrecta = 2;
                    $nuevoPuntaje = $puntosNula;
                    $totalNulas++;
                } else {
                    $ru = trim((string) $row->respuesta_usuario);
                    $rc = trim((string) $row->respuesta_correcta);

                    if ($ru === '') {
                        // blanco
                        $nuevoEsCorrecta = 2;
                        $nuevoPuntaje = $puntosNula;
                        $totalNulas++;
                    } else {
                        $ruN = mb_strtoupper($ru);
                        $rcN = mb_strtoupper($rc);

                        if ($rcN !== '' && $ruN === $rcN) {
                            $nuevoEsCorrecta = 1;
                            $nuevoPuntaje = $puntosCorrecta;
                            $totalCorrectas++;
                            $correctasPorCurso[$curso]++;
                        } else {
                            $nuevoEsCorrecta = 0;
                            $nuevoPuntaje = $puntosIncorrecta;
                            $totalIncorrectas++;
                            $incorrectasPorCurso[$curso]++;
                        }
                    }
                }

                $totalPuntos += (float) $nuevoPuntaje;

                DB::table('preguntas_asignadas')
                    ->where('id', $row->pa_id)
                    ->update([
                        'es_correcta' => $nuevoEsCorrecta,
                        'puntaje'     => $nuevoPuntaje,
                        'updated_at'  => now(),
                    ]);
            }

            // 6) Resumen
            $totalPreguntas = (int) $items->count();
            $porcentajeCorrectas = $totalPreguntas > 0 ? ($totalCorrectas / $totalPreguntas) * 100 : 0;

            $calificacionSobre20 = ($puntajeMaximo > 0)
                ? ($totalPuntos / $puntajeMaximo) * 20
                : 0;

            $correctasPorCursoFormato = [];
            foreach ($correctasPorCurso as $curso => $corr) {
                $y = $preguntasTotalesPorCurso[$curso] ?? 0;
                $correctasPorCursoFormato[$curso] = "{$corr} de {$y}";
            }

            // 7) Guardar resultado en resultados_examenes
            $resultadoId = DB::table('resultados_examenes')->insertGetId([
                'postulante_id' => $postulante->id,
                'examen_id' => $examen->id,
                'total_puntos' => round($totalPuntos, 3),
                'correctas_por_curso' => json_encode($correctasPorCursoFormato),
                'incorrectas_por_curso' => json_encode($incorrectasPorCurso),
                'preguntas_totales_por_curso' => json_encode($preguntasTotalesPorCurso),
                'total_correctas' => $totalCorrectas,
                'total_incorrectas' => $totalIncorrectas,
                'total_nulas' => $totalNulas,
                'porcentaje_correctas' => round($porcentajeCorrectas, 2),
                'calificacion_sobre_20' => round($calificacionSobre20, 2),
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            // 8) Recalcular orden de mérito por proceso
            $this->recalcularOrdenMerito($cfg->proceso_id);

            // 9) Leer orden_merito ya asignado (opcional)
            $orden = DB::table('resultados_examenes')->where('id', $resultadoId)->value('orden_merito');

            DB::table('examenes')->where('id', $examen->id)->update([
                'estado' => 'calificado',
                'hora_fin' => now(),
            ]);
            return response()->json([
                'success' => true,
                'mensaje' => 'Examen calificado exitosamente.',
                'examen_id' => $examen->id,
                'proceso_id' => $cfg->proceso_id,

                'total_puntos' => round($totalPuntos, 2),
                'total_correctas' => $totalCorrectas,
                'total_incorrectas' => $totalIncorrectas,
                'total_nulas' => $totalNulas,

                'porcentaje_correctas' => round($porcentajeCorrectas, 2),
                'calificacion_sobre_20' => round($calificacionSobre20, 2),
                'orden_merito' => $orden,

                'correctas_por_curso' => $correctasPorCursoFormato,
                'incorrectas_por_curso' => $incorrectasPorCurso,
                'preguntas_totales_por_curso' => $preguntasTotalesPorCurso,
            ]);
        });
    }


    public function recalcularOrdenMerito($procesoId): void
    {
        DB::statement("
            UPDATE resultados_examenes r
            JOIN (
                SELECT
                    r2.id,
                    ROW_NUMBER() OVER (
                        ORDER BY
                            r2.total_puntos DESC,
                            COALESCE(r2.updated_at, r2.created_at) ASC
                    ) AS nuevo_orden
                FROM resultados_examenes r2
                JOIN examenes e ON e.id = r2.examen_id
                JOIN area_proceso ap ON ap.id = e.area_proceso_id
                WHERE ap.proceso_id = ?
            ) x ON x.id = r.id
            SET r.orden_merito = x.nuevo_orden
        ", [$procesoId]);
    }





}