<?php
declare(strict_types=1);
namespace App\Models;

use App\Core\Database;
use DateInterval;
use DatePeriod;
use DateTimeImmutable;
use PDO;

final class ProfessorAgenda
{
    private const DAYS = ['lundi'=>1,'mardi'=>2,'mercredi'=>3,'jeudi'=>4,'vendredi'=>5,'samedi'=>6,'dimanche'=>7];

    public static function range(string $mode,string $anchor): array
    {
        $date=DateTimeImmutable::createFromFormat('Y-m-d',$anchor) ?: new DateTimeImmutable('today');
        if($mode==='day'){$from=$date->setTime(0,0);$to=$from->modify('+1 day');}
        elseif($mode==='month'){$from=$date->modify('first day of this month')->setTime(0,0);$to=$from->modify('+1 month');}
        else{$from=$date->modify('monday this week')->setTime(0,0);$to=$from->modify('+7 days');}
        return [$from,$to];
    }

    public static function events(int $professorId,DateTimeImmutable $from,DateTimeImmutable $to): array
    {
        $pdo=Database::connection();
        $sql="SELECT g.id groupe_id,g.code groupe_code,g.libelle groupe_libelle,g.type_groupe,g.capacite_max,
                    a.libelle atelier_libelle,a.code atelier_code,d.libelle discipline_libelle,
                    v.id planning_version_id,v.jour_semaine,v.heure_debut,v.heure_fin,
                    v.date_debut_effet,v.date_fin_effet,s.libelle salle_libelle,
                    (SELECT COUNT(*) FROM groupe_participants x WHERE x.groupe_id=g.id AND x.deleted_at IS NULL AND x.statut='actif') nb_participants
              FROM groupe_professeurs gp
              INNER JOIN groupes_cours g ON g.id=gp.groupe_id AND g.deleted_at IS NULL
              INNER JOIN ateliers a ON a.id=g.atelier_id AND a.deleted_at IS NULL
              LEFT JOIN disciplines d ON d.id=a.discipline_id
              INNER JOIN groupe_planning_versions v ON v.groupe_id=g.id
              LEFT JOIN salles s ON s.id=v.salle_id
              WHERE gp.professeur_id=:professor AND gp.actif=1
                AND v.date_debut_effet < :to_date
                AND (v.date_fin_effet IS NULL OR v.date_fin_effet >= :from_date)
              ORDER BY FIELD(v.jour_semaine,'lundi','mardi','mercredi','jeudi','vendredi','samedi','dimanche'),v.heure_debut";
        $stmt=$pdo->prepare($sql);$stmt->execute(['professor'=>$professorId,'from_date'=>$from->format('Y-m-d'),'to_date'=>$to->format('Y-m-d')]);
        $slots=$stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];$closures=self::closures($from,$to);$events=[];
        foreach(new DatePeriod($from,new DateInterval('P1D'),$to) as $day){
            $weekday=(int)$day->format('N');
            foreach($slots as $slot){
                if((self::DAYS[$slot['jour_semaine']]??0)!==$weekday)continue;
                $date=$day->format('Y-m-d');
                if($date<$slot['date_debut_effet']||(!empty($slot['date_fin_effet'])&&$date>$slot['date_fin_effet']))continue;
                $closure=self::closureFor($date,$closures);
                $events[]=$slot+['date'=>$date,'fermeture'=>$closure];
            }
        }
        usort($events,static fn($a,$b)=>[$a['date'],$a['heure_debut']]<=>[$b['date'],$b['heure_debut']]);return $events;
    }

    private static function closures(DateTimeImmutable $from,DateTimeImmutable $to): array
    {
        $stmt=Database::connection()->prepare("SELECT pf.libelle,pf.type_fermeture,pf.date_debut,pf.date_fin FROM periodes_fermeture pf INNER JOIN calendriers_scolaires c ON c.id=pf.calendrier_id AND c.actif=1 WHERE pf.date_debut < :to_date AND pf.date_fin >= :from_date ORDER BY pf.date_debut");
        $stmt->execute(['from_date'=>$from->format('Y-m-d'),'to_date'=>$to->format('Y-m-d')]);return $stmt->fetchAll(PDO::FETCH_ASSOC)?:[];
    }
    private static function closureFor(string $date,array $closures): ?array{foreach($closures as $c){if($date>=$c['date_debut']&&$date<=$c['date_fin'])return $c;}return null;}
}
