You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
5.4 KiB
PHP

<?php
namespace App\Services;
use App\Models\Examen;
use App\Models\Pregunta;
use App\Models\ReglaAreaProceso;
use App\Models\PreguntaAsignada;
use Illuminate\Support\Facades\DB;
class ExamenService
{
/**
* Generar preguntas según reglas
*/
public function generarPreguntasExamen(Examen $examen): array
{
if ($examen->preguntasAsignadas()->exists()) {
return [
'success' => false,
'message' => 'El examen ya tiene preguntas'
];
}
$reglas = ReglaAreaProceso::where('area_proceso_id', $examen->area_proceso_id)
->orderBy('orden')
->get();
if ($reglas->isEmpty()) {
return [
'success' => false,
'message' => 'No hay reglas configuradas'
];
}
DB::beginTransaction();
try {
$orden = 1;
foreach ($reglas as $regla) {
$preguntas = Pregunta::where('curso_id', $regla->curso_id)
->where('activo', 1)
->when($regla->nivel_dificultad, fn ($q) =>
$q->where('nivel_dificultad', $regla->nivel_dificultad)
)
->inRandomOrder()
->limit($regla->cantidad_preguntas)
->get();
if ($preguntas->count() < $regla->cantidad_preguntas) {
throw new \Exception("Preguntas insuficientes para curso {$regla->curso_id}");
}
foreach ($preguntas as $pregunta) {
PreguntaAsignada::create([
'examen_id' => $examen->id,
'pregunta_id' => $pregunta->id,
'orden' => $orden++,
'puntaje_base' => $regla->ponderacion,
'estado' => 'pendiente',
]);
}
}
DB::commit();
return ['success' => true];
} catch (\Throwable $e) {
DB::rollBack();
return ['success' => false, 'message' => $e->getMessage()];
}
}
public function obtenerPreguntasExamen(Examen $examen): array
{
// Traemos preguntas con curso
$preguntas = $examen->preguntasAsignadas()
->with('pregunta.curso')
->get()
->sortBy('orden');
// Traemos datos del área-proceso directamente desde la DB
$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.nombre as proceso_nombre',
'procesos.duracion as proceso_duracion',
'procesos.intentos_maximos as proceso_intentos_maximos',
'areas.nombre as area_nombre'
)
->first();
return $preguntas->map(fn($pa) => [
'id' => $pa->id,
'orden' => $pa->orden,
'enunciado' => $pa->pregunta->enunciado,
'extra' => $pa->pregunta->enunciado_adicional,
'opciones' => $this->mezclarOpciones($pa->pregunta->opciones),
'imagenes' => $pa->pregunta->imagenes,
'estado' => $pa->estado,
'respuesta' => $pa->pregunta->respuesta_correcta,
'curso' => $pa->pregunta->curso->nombre ?? null,
'proceso' => $areaProceso->proceso_nombre ?? null,
'duracion' => $areaProceso->proceso_duracion ?? null,
'intentos_maximos'=> $areaProceso->proceso_intentos_maximos ?? null,
'area' => $areaProceso->area_nombre ?? null
])->values()->toArray();
}
public function guardarRespuesta(PreguntaAsignada $pa, ?string $respuesta): array
{
if ($pa->estado === 'respondida') {
return ['success' => false, 'message' => 'Ya respondida'];
}
// 🔹 Si está en blanco
if (empty($respuesta)) {
$pa->update([
'respuesta_usuario' => null,
'es_correcta' => 2, // 2 = blanco
'puntaje_obtenido' => 0,
'estado' => 'respondida',
'respondida_at' => now()
]);
return [
'success' => true,
'correcta' => 2,
'puntaje' => 0
];
}
// 🔹 Si respondió algo
$esCorrecta = $respuesta === $pa->pregunta->respuesta_correcta;
$pa->update([
'respuesta_usuario' => $respuesta,
'es_correcta' => $esCorrecta ? 1 : 0,
'puntaje_obtenido' => $esCorrecta ? $pa->puntaje_base : 0,
'estado' => 'respondida',
'respondida_at' => now()
]);
return [
'success' => true,
'correcta' => $esCorrecta ? 1 : 0,
'puntaje' => $pa->puntaje_obtenido
];
}
/**
* Finalizar examen
*/
public function finalizarExamen(Examen $examen): void
{
$examen->update([
'estado' => 'finalizado',
'hora_fin' => now()
]);
}
private function mezclarOpciones(?array $opciones): array
{
if (!$opciones) return [];
$keys = array_keys($opciones);
shuffle($keys);
return array_map(fn ($k) => [
'key' => $k,
'texto' => $opciones[$k]
], $keys);
}
}