<?php
namespace App\Controllers;

use App\Core\{Auth,Controller,Csrf,Database,Permission};
use App\Models\Attendance;
use App\Security\SecureFileService;

final class AttendanceJustificationController extends Controller
{
    private const MAX=10485760;
    private const TYPES=['application/pdf'=>'pdf','image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp'];

    public function page(): void
    {
        Auth::requireLogin();Permission::require('presences.view');
        $session=$this->session();
        $q=Database::connection()->prepare(
            "SELECT pr.id presence_id,pr.statut,m.nom,m.prenom,
                    aj.id justificatif_id,aj.public_token justificatif_token,
                    aj.titre,aj.created_at
             FROM seance_participants sp
             JOIN membres_famille m ON m.id=sp.membre_id
             LEFT JOIN presences pr ON pr.seance_participant_id=sp.id
             LEFT JOIN absence_justificatifs aj ON aj.presence_id=pr.id
             WHERE sp.seance_id=? AND pr.statut IN('absent','absent_justifie')
             ORDER BY m.nom,m.prenom,aj.created_at DESC"
        );
        $q->execute([(int)$session['id']]);
        $this->view('attendance/justifications',[
            'pageTitle'=>'Justificatifs d’absence',
            'session'=>$session,
            'rows'=>$q->fetchAll()?:[],
        ]);
    }

    public function upload(): void
    {
        Auth::requireLogin();Permission::require('presences.edit');Csrf::verify($_POST['_csrf']??null);
        $session=$this->session((string)($_POST['seance']??''));
        $presence=(int)($_POST['presence_id']??0);
        $check=Database::connection()->prepare(
            "SELECT pr.id
             FROM presences pr
             JOIN seance_participants sp ON sp.id=pr.seance_participant_id
             WHERE pr.id=? AND sp.seance_id=? LIMIT 1"
        );
        $check->execute([$presence,(int)$session['id']]);
        if(!(int)$check->fetchColumn()) $this->notFound();

        $f=$_FILES['justificatif']??[];
        $dir=BASE_PATH.'/storage/justificatifs/'.date('Y/m');
        $stored=SecureFileService::storeUploaded($f,$dir,[
            'application/pdf'=>['pdf'],'image/jpeg'=>['jpg','jpeg'],
            'image/png'=>['png'],'image/webp'=>['webp'],
        ],self::MAX,'justificatif');
        $mime=$stored['mime'];$target=$stored['path'];
        $pdo=Database::connection();
        $pdo->beginTransaction();
        try{
            $pdo->prepare(
                "INSERT INTO absence_justificatifs(
                    presence_id,titre,nom_original,chemin_stockage,mime_type,public_token
                 ) VALUES(?,?,?,?,?,?)"
            )->execute([
                $presence,trim((string)($_POST['titre']??'Justificatif')),
                $stored['original'],str_replace(BASE_PATH.'/','',$target),
                $mime,bin2hex(random_bytes(32)),
            ]);
            $pdo->prepare(
                "UPDATE presences SET statut='absent_justifie',updated_at=NOW() WHERE id=?"
            )->execute([$presence]);
            $pdo->commit();
        }catch(\Throwable $e){$pdo->rollBack();throw $e;}
        $this->redirect('/presences/justificatifs?seance='.rawurlencode((string)$session['public_token']));
    }

    public function download(): void
    {
        Auth::requireLogin();Permission::require('presences.view');
        if(isset($_GET['id'])) $this->notFound();
        $d=$this->justification((string)($_GET['document']??''));
        $path=BASE_PATH.'/'.$d['chemin_stockage'];
        if(!is_file($path)) $this->notFound();
        $this->audit('absence_justificatif',(int)$d['id']);
        $extension=self::TYPES[$d['mime_type']]??'bin';
        header('Content-Type: '.$d['mime_type']);
        header('Content-Disposition: attachment; filename="justificatif-absence.'.$extension.'"');
        header('Content-Length: '.filesize($path));
        header('Cache-Control: private, no-store, max-age=0');
        header('Pragma: no-cache');
        header('X-Content-Type-Options: nosniff');
        readfile($path);exit;
    }

    public function archiveEmargement(): void
    {
        Auth::requireLogin();Permission::require('emargements.delete');Csrf::verify($_POST['_csrf']??null);
        $document=$this->emargement((string)($_POST['document']??''));
        Database::connection()->prepare(
            "UPDATE emargements_documents SET deleted_at=NOW() WHERE id=? AND deleted_at IS NULL"
        )->execute([(int)$document['id']]);
        $this->redirect('/presences/emargements?seance='.rawurlencode((string)$document['session_token']));
    }

    private function session(?string $token=null): array
    {
        if(isset($_GET['id'])||isset($_POST['seance_id'])) $this->notFound();
        $row=Attendance::resolveSession(
            (string)($token??($_GET['seance']??'')),
            $this->organisationId(),
            Attendance::professorForUser((int)Auth::id())
        );
        if(!$row) $this->notFound();
        return $row;
    }

    private function justification(string $token): array
    {
        if(!preg_match('/\A[a-f0-9]{64}\z/',strtolower($token))) $this->notFound();
        $sql=
            "SELECT aj.*,se.professeur_id
             FROM absence_justificatifs aj
             JOIN presences pr ON pr.id=aj.presence_id
             JOIN seance_participants sp ON sp.id=pr.seance_participant_id
             JOIN seances se ON se.id=sp.seance_id AND se.deleted_at IS NULL
             JOIN groupes_cours g ON g.id=se.groupe_id
             JOIN ateliers a ON a.id=g.atelier_id
             WHERE aj.public_token=? AND a.organisation_id=?";
        $params=[strtolower($token),$this->organisationId()];
        $own=Attendance::professorForUser((int)Auth::id());
        if($own>0){$sql.=" AND se.professeur_id=?";$params[]=$own;}
        $sql.=" LIMIT 1";
        $q=Database::connection()->prepare($sql);$q->execute($params);
        $row=$q->fetch();if(!$row)$this->notFound();return$row;
    }

    private function emargement(string $token): array
    {
        if(!preg_match('/\A[a-f0-9]{64}\z/',strtolower($token))) $this->notFound();
        $q=Database::connection()->prepare(
            "SELECT d.id,se.public_token session_token
             FROM emargements_documents d
             JOIN seances se ON se.id=d.seance_id
             JOIN groupes_cours g ON g.id=se.groupe_id
             JOIN ateliers a ON a.id=g.atelier_id
             WHERE d.public_token=? AND d.deleted_at IS NULL
               AND se.deleted_at IS NULL AND a.organisation_id=? LIMIT 1"
        );
        $q->execute([strtolower($token),$this->organisationId()]);
        $row=$q->fetch();if(!$row)$this->notFound();return$row;
    }

    private function audit(string $type,int $id): void
    {
        Database::connection()->prepare(
            "INSERT INTO audit_logs(organisation_id,utilisateur_id,action,module,entite_type,entite_id,description)
             VALUES(?,?,'download','attendance',?,?, 'Téléchargement sécurisé')"
        )->execute([$this->organisationId(),(int)(Auth::id()?:0)?:null,$type,$id]);
    }
    private function organisationId():int{return(int)(Auth::user()['organisation_id']??1);}
    private function notFound():never{http_response_code(404);exit('Ressource introuvable.');}
}
