<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class Concurso extends Model
{
    protected $fillable = [
        'nombre', 'sigla', 'slug', 'patrocinador', 'anio',
        'etapa', 'nivel', 'categoria', 'nivel_educativo', 'grado',
        'num_preguntas', 'puntos_por_pregunta', 'puntos_variable',
        'modo_clasificacion', 'num_clasificados_general',
        'num_clasificados_mujer', 'num_clasificados_varon',
        'fecha_concurso', 'descripcion', 'imagen', 'estado', 'noticia_id',
    ];

    protected $casts = [
        'puntos_variable'   => 'boolean',
        'fecha_concurso'    => 'date',
        'puntos_por_pregunta' => 'float',
    ];

    // ── Auto-slug ─────────────────────────────────────────────────────
    protected static function boot()
    {
        parent::boot();
        static::creating(function ($concurso) {
            if (empty($concurso->slug)) {
                $concurso->slug = Str::slug($concurso->nombre . ' ' . $concurso->anio);
            }
        });
    }

    // ── Relaciones ───────────────────────────────────────────────────
    public function preguntas()
    {
        return $this->hasMany(ConcursoPregunta::class)->orderBy('numero');
    }

    public function participantes()
    {
        return $this->hasMany(ConcursoParticipante::class);
    }

    public function noticia()
    {
        return $this->belongsTo(Noticia::class);
    }

    // ── Lógica de negocio ────────────────────────────────────────────

    /**
     * Devuelve los participantes con su nota calculada y si son clasificados.
     * Ordenados: mayor nota primero, luego menor tiempo.
     */
    public function participantesConNota()
    {
        $preguntas     = $this->preguntas->keyBy('numero');
        $puntoGlobal   = $this->puntos_por_pregunta;

        $participantes = $this->participantes()
            ->with('respuestas')
            ->get()
            ->map(function ($p) use ($preguntas, $puntoGlobal) {
                $nota = 0;
                $respuestasIndexed = $p->respuestas->keyBy('pregunta_numero');

                foreach ($preguntas as $num => $preg) {
                    $pts      = $preg->puntos ?? $puntoGlobal;
                    $respAlu  = $respuestasIndexed->get($num);
                    $alumRaw  = $respAlu ? trim((string) $respAlu->respuesta_alumno) : null;
                    $corrRaw  = trim((string) $preg->respuesta_correcta);

                    if ($alumRaw !== null && $alumRaw !== '' && $alumRaw === $corrRaw) {
                        $nota += $pts;
                    }
                }

                $p->nota_calculada = $nota;
                return $p;
            })
            ->sortBy([
                ['nota_calculada', 'desc'],
                ['tiempo',         'asc'],
            ])
            ->values();

        // Marcar clasificados
        $this->marcarClasificados($participantes);

        return $participantes;
    }

    /**
     * Añade el atributo `clasificado` a cada participante.
     */
    private function marcarClasificados($participantes)
    {
        $modo = $this->modo_clasificacion;

        if ($modo === 'general' || $modo === 'ambos') {
            $n = $this->num_clasificados_general;
            $participantes->take($n)->each(fn($p) => $p->clasificado_general = true);
        }

        if ($modo === 'genero' || $modo === 'ambos') {
            $nF = $this->num_clasificados_mujer;
            $nM = $this->num_clasificados_varon;

            $mujeres = $participantes->filter(fn($p) => $p->genero === 'F');
            $varones = $participantes->filter(fn($p) => $p->genero === 'M');

            $mujeres->take($nF)->each(fn($p) => $p->clasificado_mujer = true);
            $varones->take($nM)->each(fn($p) => $p->clasificado_varon = true);
        }

        // Unificar en una propiedad "clasificado"
        $participantes->each(function ($p) {
            $p->clasificado = ($p->clasificado_general ?? false)
                           || ($p->clasificado_mujer   ?? false)
                           || ($p->clasificado_varon   ?? false);
        });
    }

    /**
     * Puntaje máximo posible del concurso.
     */
    public function puntajeMaximo(): float
    {
        if ($this->puntos_variable) {
            return $this->preguntas->sum(fn($p) => $p->puntos ?? $this->puntos_por_pregunta);
        }
        return $this->num_preguntas * $this->puntos_por_pregunta;
    }
}
