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

use App\Core\Database;
use DateTimeImmutable;
use InvalidArgumentException;
use PDO;

final class PlanningRepository
{
    private PDO $pdo;
    public function __construct(){ $this->pdo=Database::connection(); }
    public function calendars(): array { return $this->pdo->query("SELECT * FROM axiom_planning_calendars WHERE archived_at IS NULL ORDER BY name")->fetchAll()?:[]; }
    public function resources(): array { return $this->pdo->query("SELECT * FROM axiom_planning_resources WHERE archived_at IS NULL ORDER BY type,name")->fetchAll()?:[]; }
    public function range(string $view,string $anchor): array {
        $d=new DateTimeImmutable($anchor);
        if($view==='day') return [$d->format('Y-m-d 00:00:00'),$d->modify('+1 day')->format('Y-m-d 00:00:00')];
        if($view==='month'){ $f=$d->modify('first day of this month')->setTime(0,0); return [$f->format('Y-m-d H:i:s'),$f->modify('+1 month')->format('Y-m-d H:i:s')]; }
        $f=$d->modify('monday this week')->setTime(0,0); return [$f->format('Y-m-d H:i:s'),$f->modify('+7 days')->format('Y-m-d H:i:s')];
    }
    public function events(string $from,string $to,int $calendarId=0): array {
        $sql="SELECT e.*,c.name calendar_name,c.color calendar_color,r.name resource_name,r.type resource_type FROM axiom_planning_events e JOIN axiom_planning_calendars c ON c.id=e.calendar_id LEFT JOIN axiom_planning_resources r ON r.id=e.resource_id WHERE e.cancelled_at IS NULL AND e.start_at < ? AND e.end_at > ?";
        $args=[$to,$from]; if($calendarId>0){$sql.=' AND e.calendar_id=?';$args[]=$calendarId;} $sql.=' ORDER BY e.start_at,e.end_at';
        $s=$this->pdo->prepare($sql);$s->execute($args);return $s->fetchAll()?:[];
    }
    public function absences(string $from,string $to): array { $s=$this->pdo->prepare("SELECT a.*,r.name resource_name FROM axiom_planning_absences a JOIN axiom_planning_resources r ON r.id=a.resource_id WHERE a.archived_at IS NULL AND a.start_at < ? AND a.end_at > ? ORDER BY a.start_at");$s->execute([$to,$from]);return $s->fetchAll()?:[]; }
    public function conflicts(string $from,string $to): array { $s=$this->pdo->prepare("SELECT c.*,e1.title first_title,e2.title second_title,r.name resource_name FROM axiom_planning_conflicts c JOIN axiom_planning_events e1 ON e1.id=c.event_id JOIN axiom_planning_events e2 ON e2.id=c.conflicting_event_id LEFT JOIN axiom_planning_resources r ON r.id=c.resource_id WHERE c.resolved_at IS NULL AND e1.start_at < ? AND e1.end_at > ? ORDER BY c.detected_at DESC");$s->execute([$to,$from]);return $s->fetchAll()?:[]; }
    public function saveCalendar(array $i): int { $code=$this->code($i['code']??'');$name=trim((string)($i['name']??''));if(!$code||!$name)throw new InvalidArgumentException('Code et nom obligatoires.');$color=preg_match('/^#[0-9a-fA-F]{6}$/',(string)($i['color']??''))?(string)$i['color']:'#365CF5';$s=$this->pdo->prepare("INSERT INTO axiom_planning_calendars(code,name,description,color,timezone,active) VALUES(?,?,?,?,?,1) ON DUPLICATE KEY UPDATE name=VALUES(name),description=VALUES(description),color=VALUES(color),timezone=VALUES(timezone),active=1,archived_at=NULL");$s->execute([$code,$name,trim((string)($i['description']??'')),$color,trim((string)($i['timezone']??'Europe/Paris'))]);return (int)$this->pdo->lastInsertId(); }
    public function saveResource(array $i): int { $type=in_array($i['type']??'', ['person','room','vehicle','equipment','other'],true)?$i['type']:'other';$code=$this->code($i['code']??'');$name=trim((string)($i['name']??''));if(!$code||!$name)throw new InvalidArgumentException('Code et nom de ressource obligatoires.');$cap=max(0,(int)($i['capacity']??0));$s=$this->pdo->prepare("INSERT INTO axiom_planning_resources(code,name,type,capacity,location,active) VALUES(?,?,?,?,?,1) ON DUPLICATE KEY UPDATE name=VALUES(name),type=VALUES(type),capacity=VALUES(capacity),location=VALUES(location),active=1,archived_at=NULL");$s->execute([$code,$name,$type,$cap,trim((string)($i['location']??''))]);return (int)$this->pdo->lastInsertId(); }
    public function saveEvent(array $i,?int $uid): int {
        $cal=max(0,(int)($i['calendar_id']??0));$res=max(0,(int)($i['resource_id']??0))?:null;$title=trim((string)($i['title']??''));$start=$this->dt($i['start_at']??'');$end=$this->dt($i['end_at']??'');if($cal<=0||!$title||!$start||!$end||$end<=$start)throw new InvalidArgumentException('Agenda, titre et période valide obligatoires.');
        $this->pdo->beginTransaction();try{$s=$this->pdo->prepare("INSERT INTO axiom_planning_events(uuid,calendar_id,resource_id,title,description,location,start_at,end_at,all_day,status,created_by,updated_by) VALUES(UUID(),?,?,?,?,?,?,?,?,?,?,?)");$s->execute([$cal,$res,$title,trim((string)($i['description']??'')),trim((string)($i['location']??'')),$start,$end,!empty($i['all_day'])?1:0,'confirmed',$uid,$uid]);$id=(int)$this->pdo->lastInsertId();$this->detectConflicts($id,$res,$start,$end);$this->pdo->commit();return $id;}catch(\Throwable $e){if($this->pdo->inTransaction())$this->pdo->rollBack();throw $e;}
    }
    public function saveAbsence(array $i,?int $uid): int { $r=max(0,(int)($i['resource_id']??0));$start=$this->dt($i['start_at']??'');$end=$this->dt($i['end_at']??'');$label=trim((string)($i['label']??''));if($r<=0||!$start||!$end||$end<=$start||!$label)throw new InvalidArgumentException('Ressource, motif et période valide obligatoires.');$s=$this->pdo->prepare("INSERT INTO axiom_planning_absences(resource_id,label,start_at,end_at,notes,created_by) VALUES(?,?,?,?,?,?)");$s->execute([$r,$label,$start,$end,trim((string)($i['notes']??'')),$uid]);return (int)$this->pdo->lastInsertId(); }
    public function deleteEvent(int $id): void { if($id<=0)throw new InvalidArgumentException('Événement invalide.');$s=$this->pdo->prepare("UPDATE axiom_planning_events SET status='cancelled',cancelled_at=NOW() WHERE id=?");$s->execute([$id]);$this->pdo->prepare("UPDATE axiom_planning_conflicts SET resolved_at=NOW() WHERE event_id=? OR conflicting_event_id=?")->execute([$id,$id]); }
    private function detectConflicts(int $id,?int $res,string $start,string $end): void { if(!$res)return;$s=$this->pdo->prepare("SELECT id FROM axiom_planning_events WHERE id<>? AND resource_id=? AND cancelled_at IS NULL AND start_at < ? AND end_at > ?");$s->execute([$id,$res,$end,$start]);foreach($s->fetchAll() as $row){$a=min($id,(int)$row['id']);$b=max($id,(int)$row['id']);$q=$this->pdo->prepare("INSERT IGNORE INTO axiom_planning_conflicts(event_id,conflicting_event_id,resource_id,conflict_type,details) VALUES(?,?,?,'overlap','Chevauchement de créneaux sur une même ressource')");$q->execute([$a,$b,$res]);} }
    private function code(string $v): string { return trim(preg_replace('/[^a-z0-9._-]+/','-',strtolower($v))??'','-'); }
    private function dt(string $v): ?string { if(!$v)return null;$d=DateTimeImmutable::createFromFormat('Y-m-d\TH:i',$v)?:DateTimeImmutable::createFromFormat('Y-m-d H:i:s',$v);return $d?$d->format('Y-m-d H:i:s'):null; }
}
