<?php

namespace App\Http\Controllers;

use App\Models\Admision;
use App\Models\Horario;
use App\Models\Matricula;
use App\Models\Periodo;
use App\Models\PlanEstudio;
use App\Models\Postulante;
use App\Models\ResultadoAdmision;
use App\Models\Seccion;
use App\Models\Semestre;
use App\Models\Turno;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Inertia\Inertia;
use Inertia\Response;
use Throwable;

class MatriculaIngresanteController extends Controller
{
    /**
     * Muestra la vista base de la matrícula masiva (sin parámetros en la URL).
     */
    public function index(): Response
    {
        $primerSemestre = Semestre::orderBy('id', 'asc')->first();

        return Inertia::render('Matriculas/MatriculaIngresantes', [
            'admisiones' => Admision::query()->where('activo', 1)->select('id_admision', 'nombre')->orderByDesc('id_admision')->get(),
            'periodos'   => Periodo::query()->where('activo', 1)->select('id', 'nombre')->get(),
            'planesEstudio' => PlanEstudio::query()->select('id', 'nombre', 'codigo')->orderBy('nombre')->get(),
            'turnos'     => Turno::query()->select('id', 'nombre')->get(),
            'primerSemestre' => $primerSemestre,
        ]);
    }

    /**
     * Endpoint AJAX (Axios): Devuelve la lista de ingresantes y las secciones del 1er Semestre con oferta real.
     */
    public function obtenerDatosAjax(Request $request): JsonResponse
    {
        $idProceso = $request->input('id_proceso');
        $idPeriodo = $request->input('periodo_id');
        $idPlan    = $request->input('plan_estudio_id');

        if (!$idProceso || !$idPlan || !$idPeriodo) {
            return response()->json([
                'ingresantes' => [],
                'secciones'   => [],
            ]);
        }

        $primerSemestre = Semestre::orderBy('id', 'asc')->first();
        $semestreId = $primerSemestre ? $primerSemestre->id : 1;

        // 1. Obtener Postulantes con Vacante
        $resultados = ResultadoAdmision::query()
            ->where('id_proceso', $idProceso)
            ->where('plan_estudio_id', $idPlan)
            ->where('estado', 'con_vacante')
            ->with([
                'postulante:id_postulante,codigo_postulante,nombres,apellidos,dni,email,telefono,usuario_id',
                'planEstudio:id,nombre,codigo',
            ])
            ->get();

        $ingresantes = [];
        foreach ($resultados as $res) {
            $p = $res->postulante;
            if (!$p) continue;

            $yaMatriculado = Matricula::where('postulante_id', $p->id_postulante)
                ->where('periodo_id', $idPeriodo)
                ->exists();

            $tieneUsuario = !is_null($p->usuario_id) || DB::table('usuarios')->where('username', $p->dni)->exists();

            $ingresantes[] = [
                'id_resultado'      => $res->id,
                'postulante_id'     => $p->id_postulante,
                'codigo_postulante' => $p->codigo_postulante,
                'nombres'           => $p->nombres,
                'apellidos'         => $p->apellidos,
                'dni'               => $p->dni,
                'email'             => $p->email,
                'plan_estudio_id'   => $res->plan_estudio_id,
                'plan_nombre'       => $res->planEstudio?->nombre,
                'nota'              => $res->nota,
                'ya_matriculado'    => $yaMatriculado,
                'tiene_usuario'     => $tieneUsuario,
            ];
        }

        // 2. Obtener Secciones con programación real para el 1er Semestre de este Plan de Estudios
        $seccionIds = Horario::query()
            ->where('id_periodo', $idPeriodo)
            ->whereHas('curso', function ($q) use ($semestreId, $idPlan) {
                $q->where('semestre_id', $semestreId)
                  ->whereHas('planesEstudio', fn ($p) => $p->where('plan_estudio_id', $idPlan));
            })
            ->whereNotNull('id_seccion')
            ->pluck('id_seccion')
            ->unique()
            ->toArray();

        $seccionesDisponibles = Seccion::query()
            ->whereIn('id', $seccionIds)
            ->select('id', 'nombre')
            ->orderBy('nombre')
            ->get();

        return response()->json([
            'ingresantes' => $ingresantes,
            'secciones'   => $seccionesDisponibles,
        ]);
    }

    /**
     * Procesa la matrícula masiva del grupo seleccionado.
     */
    public function store(Request $request): RedirectResponse
    {
        $datos = $request->validate([
            'id_proceso' => ['required', 'integer', 'exists:admisiones,id_admision'],
            'periodo_id' => ['required', 'integer', 'exists:periodos,id'],
            'plan_estudio_id' => ['required', 'integer', 'exists:planes_estudio,id'],
            'semestre_id' => ['required', 'integer', 'exists:semestres,id'],
            'seccion_id' => ['required', 'integer', 'exists:secciones,id'],
            'turno_id' => ['nullable', 'integer', 'exists:turnos,id'],
            'postulantes_ids' => ['required', 'array', 'min:1'],
            'postulantes_ids.*' => ['required', 'integer', 'exists:postulantes,id_postulante'],
        ], [
            'id_proceso.required' => 'Seleccione el proceso de admisión.',
            'periodo_id.required' => 'Seleccione el periodo lectivo activo.',
            'plan_estudio_id.required' => 'Seleccione el plan de estudios.',
            'seccion_id.required' => 'Seleccione la sección asignada.',
            'postulantes_ids.required' => 'Seleccione al menos un ingresante a matricular.',
        ]);

        try {
            DB::transaction(function () use ($datos) {
                $añoActual = date('Y');

                $rolEstudiante = DB::table('roles')->where('nombre', 'Estudiante')->first();
                $rolEstudianteId = $rolEstudiante ? $rolEstudiante->id : null;

                $horariosPrimerCiclo = Horario::where('id_periodo', $datos['periodo_id'])
                    ->where('id_seccion', $datos['seccion_id'])
                    ->when($datos['turno_id'] ?? null, fn ($q, $tId) => $q->where('id_turno', $tId))
                    ->whereHas('curso', function ($q) use ($datos) {
                        $q->where('semestre_id', $datos['semestre_id'])
                          ->whereHas('planesEstudio', fn ($p) => $p->where('plan_estudio_id', $datos['plan_estudio_id']));
                    })
                    ->get();

                if ($horariosPrimerCiclo->isEmpty()) {
                    throw new \Exception("La sección elegida no posee horarios programados en el 1er Semestre para este Plan de Estudios.");
                }

                foreach ($datos['postulantes_ids'] as $postulanteId) {
                    $postulante = Postulante::find($postulanteId);
                    if (!$postulante) continue;

                    $matricula = Matricula::firstOrNew([
                        'postulante_id' => $postulanteId,
                        'periodo_id' => $datos['periodo_id'],
                    ]);

                    if (!$matricula->exists) {
                        $ultimoId = Matricula::max('id') ?? 0;
                        $matricula->codigo_matricula = 'MAT-' . $añoActual . '-' . str_pad($ultimoId + 1, 4, '0', STR_PAD_LEFT);
                    }

                    $matricula->plan_estudio_id = $datos['plan_estudio_id'];
                    $matricula->semestre_id = $datos['semestre_id'];
                    $matricula->estado = 'Matriculado';
                    $matricula->fecha_matricula = now();
                    $matricula->save();

                    foreach ($horariosPrimerCiclo as $horario) {
                        $matricula->cursosMatriculados()->updateOrCreate(
                            ['horario_id' => $horario->id],
                            [
                                'curso_id' => $horario->id_curso,
                                'estado' => 'Inscrito',
                            ]
                        );
                    }

                    $usuarioId = $postulante->usuario_id;

                    if (!$usuarioId) {
                        $usuarioExistente = DB::table('usuarios')->where('username', $postulante->dni)->first();

                        if ($usuarioExistente) {
                            $usuarioId = $usuarioExistente->id;
                        } else {
                            $usuarioId = DB::table('usuarios')->insertGetId([
                                'username'      => $postulante->dni,
                                'password_hash' => Hash::make($postulante->dni),
                                'status'        => 'Disponible',
                                'created_at'    => now(),
                            ]);
                        }

                        $postulante->usuario_id = $usuarioId;
                    }

                    $postulante->grado = 'Estudiante';
                    $postulante->save();

                    if ($rolEstudianteId && $usuarioId) {
                        DB::table('usuario_roles')->updateOrInsert(
                            [
                                'usuario_id' => $usuarioId,
                                'rol_id'     => $rolEstudianteId,
                            ],
                            [
                                'updated_at' => now(),
                                'created_at' => now(),
                            ]
                        );
                    }
                }
            });

            return back()->with('success', 'Ingresantes matriculados exitosamente en la sección elegida y usuarios registrados.');
        } catch (Throwable $e) {
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }
}