<?php
declare(strict_types=1);
namespace App\Controllers;
use App\Core\{Auth,Controller,Csrf,Permission};
use App\Models\DisciplinePlanning;
use App\Models\EnrollmentRequest;
use App\Models\ProfessorRemoteWork;
use App\Models\ProfessorYear;
use App\Models\ProfessorPlanningEvent;
use App\Services\EnrollmentConfirmationService;

final class DisciplinePlanningController extends Controller
{
    private function org():int{return (int)(Auth::user()['organisation_id']??1);}
    public function index():void{Auth::requireLogin();Permission::require('demandes_inscription.review');$this->view('discipline_planning/index',['pageTitle'=>'Pilotage des disciplines','disciplines'=>DisciplinePlanning::dashboard($this->org())]);}
    public function statuses():void{Auth::requireLogin();Permission::require('demandes_inscription.validate');Csrf::verify($_POST['_csrf']??null);DisciplinePlanning::saveStatuses($this->org(),$_POST['status']??[],(int)Auth::id());$_SESSION['success']='Les statuts annuels des disciplines ont été enregistrés.';$this->redirect('/pilotage-disciplines');}
    private function ownProfessor():int{
        $q=\App\Core\Database::connection()->prepare("SELECT id FROM professeurs WHERE utilisateur_id=? AND organisation_id=? AND deleted_at IS NULL LIMIT 1");
        $q->execute([(int)Auth::id(),$this->org()]);return (int)$q->fetchColumn();
    }
    private function directionMode():bool{
        return ($_GET['mode']??$_POST['mode']??'')==='direction'
            && Permission::canViewFullProfessorRh()
            && Permission::can('professeurs.disciplines.manage');
    }
    private function requestedProfessor():int{
        $asked=(int)($_POST['professeur_id']??0);
        $token=trim((string)($_GET['professeur']??''));
        if($token!==''){
            $q=\App\Core\Database::connection()->prepare(
                "SELECT id FROM professeurs
                 WHERE public_token=? AND organisation_id=? AND deleted_at IS NULL LIMIT 1"
            );
            $q->execute([$token,$this->org()]);
            $asked=(int)$q->fetchColumn();
            if($asked<=0)throw new \RuntimeException('Professeur introuvable.');
        }elseif($_SERVER['REQUEST_METHOD']==='GET' && isset($_GET['id'])){
            throw new \RuntimeException('Cette ancienne adresse n’est plus autorisée.');
        }
        if($this->directionMode())return $asked;
        $own=$this->ownProfessor();
        if($own>0&&(!$asked||$asked===$own))return $own;
        // En mode test Professeur, l'identité métier est portée par la session
        // canonique PortalSimulation. Le changement d'espace masque
        // volontairement les permissions Direction : il ne faut donc jamais
        // les utiliser pour reconnaître le professeur simulé.
        if(Permission::activeSpace()==='professeur'&&Permission::isSuperAdmin()){
            $simulated=\App\Core\PortalSimulation::professorId();
            if($simulated!==null&&(!$asked||$asked===$simulated))return $simulated;
        }
        $preview=(int)($_SESSION['pedagogical_professor_id']??0);
        if(Permission::canViewFullProfessorRh()&&$preview>0&&(!$asked||$asked===$preview))return $preview;
        throw new \RuntimeException('Accès refusé à ce planning.');
    }

    private function professorUrl(int $id,string $path):string{
        $q=\App\Core\Database::connection()->prepare(
            "SELECT public_token FROM professeurs
             WHERE id=? AND organisation_id=? AND deleted_at IS NULL LIMIT 1"
        );
        $q->execute([$id,$this->org()]);
        $token=(string)$q->fetchColumn();
        if($token==='')throw new \RuntimeException('Professeur introuvable.');
        return $path.'?professeur='.rawurlencode($token);
    }
    public function professor():void{
        Auth::requireLogin();
        $id=$this->requestedProfessor();
        $canManage=$this->directionMode();
        $data=DisciplinePlanning::professorData($this->org(),$id);
        // Les panneaux télétravail et réunions sont complémentaires au planning.
        // Une structure optionnelle ancienne ne doit jamais empêcher l'ouverture
        // du planning principal.
        $data['remote_work_items']=[];
        $data['planning_events']=['events'=>[],'requests'=>[]];
        $optionalWarnings=[];
        try{
            $data['remote_work_items']=ProfessorRemoteWork::all($this->org(),$id,date('Y-m'));
        }catch(\Throwable $e){
            $optionalWarnings[]='Le panneau Télétravail est momentanément indisponible.';
            error_log('CDA planning remote work: '.$e->getMessage());
        }
        try{
            ProfessorPlanningEvent::ensureStorage();
            $data['planning_events']=ProfessorPlanningEvent::all($this->org(),$id);
        }catch(\Throwable $e){
            $optionalWarnings[]='Le panneau Réunions est momentanément indisponible.';
            error_log('CDA planning events: '.$e->getMessage());
        }
        if($optionalWarnings){
            $data['error']=implode(' ',$optionalWarnings);
        }
        $data['canAddMeeting']=$canManage||(!$canManage&&$this->ownProfessor()===$id&&!empty($data['professor']['reunions_autorisees']));
        $this->view('discipline_planning/professor',['pageTitle'=>'Planning prévisionnel','canManage'=>$canManage,'directionMode'=>$canManage]+$data);
    }
    public function waiting():void{Auth::requireLogin();$id=$this->requestedProfessor();$data=DisciplinePlanning::professorData($this->org(),$id);$this->view('professors_pro/waiting',['pageTitle'=>'Affecter un élève en attente']+$data);}
    public function assignmentValidations():void{
        Auth::requireLogin();
        if (!Permission::canValidateAssignments()) {
            http_response_code(403);
            exit('Accès réservé à la Direction.');
        }
        $this->view('discipline_planning/assignment_validations',[
            'pageTitle'=>'Affectations à valider',
            'proposals'=>DisciplinePlanning::proposalsForDirection($this->org())
        ]);
    }
    public function slot():void{Auth::requireLogin();Permission::require('professeurs.disciplines.manage');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['professeur_id']??0);try{DisciplinePlanning::saveSlot($this->org(),$id,$_POST,(int)Auth::id());$_SESSION['success']='Plage ajoutée au planning.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning').'&mode=direction');}
    public function updateSlot():void{Auth::requireLogin();Permission::require('professeurs.disciplines.manage');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['professeur_id']??0);try{DisciplinePlanning::updateSlot($this->org(),$id,(int)($_POST['slot_id']??0),$_POST,(int)Auth::id());$_SESSION['success']='La plage a été modifiée dans le planning.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning').'&mode=direction');}
    public function requestMove():void{Auth::requireLogin();Csrf::verify($_POST['_csrf']??null);$id=$this->requestedProfessor();try{ProfessorPlanningEvent::requestMove($this->org(),$id,$_POST,(int)Auth::id());$_SESSION['success']='Votre demande de déplacement a été envoyée à la Direction.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning'));}
    public function decideMove():void{Auth::requireLogin();Permission::require('professeurs.disciplines.manage');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['professeur_id']??0);try{ProfessorPlanningEvent::decideMove($this->org(),(int)($_POST['request_id']??0),($_POST['decision']??'')==='valider',(string)($_POST['commentaire']??''),(int)Auth::id());$_SESSION['success']='La demande de déplacement a été traitée.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning').'&mode=direction');}
    public function meeting():void{
        Auth::requireLogin();Csrf::verify($_POST['_csrf']??null);
        $direction=Permission::can('professeurs.disciplines.manage')&&Permission::canViewFullProfessorRh();
        $id=(int)($_POST['professeur_id']??0);
        if($direction){
            $ids=array_values(array_filter(array_map('intval',(array)($_POST['professeur_ids']??[]))));
        }else{
            $id=$this->requestedProfessor();
            $q=\App\Core\Database::connection()->prepare("SELECT reunions_autorisees FROM professeurs WHERE id=? AND organisation_id=? AND deleted_at IS NULL");
            $q->execute([$id,$this->org()]);
            if((int)$q->fetchColumn()!==1){http_response_code(403);exit('La Direction ne vous a pas autorisé à ajouter des réunions.');}
            $ids=[$id];
        }
        try{ProfessorPlanningEvent::createMeeting($this->org(),$ids,$_POST,(int)Auth::id());$_SESSION['success']=$direction?'La réunion a été ajoutée aux plannings prévisionnels des professeurs invités.':'La réunion a été ajoutée à votre planning.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}
        $this->redirect($this->professorUrl($id,'/professeurs-pro/planning').($direction?'&mode=direction':''));
    }
    public function archiveSlot():void{Auth::requireLogin();Permission::requireAny('planning_slots.archive','professeurs.disciplines.manage');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['professeur_id']??0);try{\App\Services\AdminTrashService::archive('slot',(int)($_POST['slot_id']??0),$this->org(),(int)Auth::id(),'Créneau de planning professeur',(string)($_POST['reason']??''));$_SESSION['success']='Le créneau a été archivé.';}catch(\Throwable$e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning').'&mode=direction');}
    public function validatePlanning():void{Auth::requireLogin();Permission::require('demandes_inscription.validate');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['professeur_id']??0);try{DisciplinePlanning::validatePlanning($this->org(),$id,(int)Auth::id());$yearId=DisciplinePlanning::activeYearId($this->org());$generated=$yearId?ProfessorYear::generate($this->org(),$id,$yearId,(int)Auth::id()):0;$_SESSION['success']='Planning validé définitivement. '.$generated.' cours ont été générés dans le calendrier annuel.';}catch(\Throwable $e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/planning').'&mode=direction');}
    public function proposeStudent():void{Auth::requireLogin();Csrf::verify($_POST['_csrf']??null);$id=$this->requestedProfessor();try{DisciplinePlanning::proposeStudent($this->org(),$id,(int)($_POST['slot_id']??0),(int)($_POST['demande_inscription_id']??0),(int)Auth::id(),(string)($_POST['commentaire']??''));$_SESSION['success']='Affectation proposée à la Direction. La place est réservée jusqu’à sa décision.';}catch(\Throwable$e){$_SESSION['error']=$e->getMessage();}$this->redirect($this->professorUrl($id,'/professeurs-pro/attente'));}
    public function decideStudent():void{
        Auth::requireLogin();
        if (!Permission::canValidateAssignments()) {
            http_response_code(403);
            exit('Accès réservé à la Direction.');
        }
        Csrf::verify($_POST['_csrf']??null);
        $proposalId=(int)($_POST['proposal_id']??0);$approve=($_POST['decision']??'')==='valider';
        try{
            $proposal=DisciplinePlanning::proposal($this->org(),$proposalId);
            if(!$proposal)throw new \RuntimeException('Cette proposition a déjà été traitée.');
            if($approve){
                $result=EnrollmentRequest::validateSlot((int)$proposal['demande_inscription_id'],$this->org(),(int)$proposal['slot_id'],(int)Auth::id());
                EnrollmentConfirmationService::send($result,(int)Auth::id());
            }
            DisciplinePlanning::finishProposal($this->org(),$proposalId,$approve,(int)Auth::id(),(string)($_POST['commentaire_decision']??''));
            $_SESSION['success']=$approve?'Affectation validée par la Direction.':'Proposition refusée ; l’élève est replacé en file d’attente.';
        }catch(\Throwable$e){$_SESSION['error']=$e->getMessage();}
        $this->redirect('/validations-affectations');
    }
}
