<?php
declare(strict_types=1);
namespace App\Services;
use App\Repositories\AppointmentRepository;
use InvalidArgumentException;use RuntimeException;
final class AppointmentService{
 public function __construct(private ?AppointmentRepository $appointments=null){$this->appointments??=new AppointmentRepository();}
 public function list(array $f,?int $tid=null):array{return$this->appointments->list($f,$tid);}public function find(int $id):array{$r=$this->appointments->find($id);if($r===null)throw new RuntimeException('Appointment not found.',404);return$r;}
 public function formData(?int $tid=null):array{return['patients'=>$tid!==null?$this->appointments->patientsForTherapist($tid):$this->appointments->patients(),'therapists'=>$tid!==null?array_values(array_filter($this->appointments->therapists(),fn($t)=>(int)$t['id']===$tid)):$this->appointments->therapists(),'services'=>$this->appointments->services()];}
 public function create(array $d,int $actor,?int $forced=null):int{$x=$this->validate($d,$forced);$x['created_by']=$actor;return$this->appointments->create($x);}public function update(int $id,array $d,?int $forced=null):void{$this->appointments->update($id,$this->validate($d,$forced));}
 public function markStatus(int $id,string $status):void{if(!in_array($status,['completed','no_show'],true))throw new InvalidArgumentException('Invalid appointment status.');$a=$this->find($id);if(!in_array($a['status'],['scheduled','confirmed'],true))throw new InvalidArgumentException('Only scheduled or confirmed appointments can be updated.');$this->appointments->update($id,['patient_id'=>(int)$a['patient_id'],'therapist_id'=>(int)$a['therapist_id'],'service_id'=>$a['service_id']!==null?(int)$a['service_id']:null,'appointment_date'=>$a['appointment_date'],'start_time'=>$a['start_time'],'end_time'=>$a['end_time'],'status'=>$status,'notes'=>$a['notes']]);}
 public function cancel(int $id):void{$a=$this->find($id);if(!in_array($a['status'],['scheduled','confirmed'],true))throw new InvalidArgumentException('Only scheduled or confirmed appointments can be cancelled.');$this->appointments->update($id,['patient_id'=>(int)$a['patient_id'],'therapist_id'=>(int)$a['therapist_id'],'service_id'=>$a['service_id']!==null?(int)$a['service_id']:null,'appointment_date'=>$a['appointment_date'],'start_time'=>$a['start_time'],'end_time'=>$a['end_time'],'status'=>'cancelled','notes'=>$a['notes']]);}
 private function validate(array $d,?int $forced):array{$p=(int)($d['patient_id']??0);$t=$forced??(int)($d['therapist_id']??0);$s=(int)($d['service_id']??0);$date=trim((string)($d['appointment_date']??''));$start=trim((string)($d['start_time']??''));$end=trim((string)($d['end_time']??''));$status=(string)($d['status']??'scheduled');if($p<1)throw new InvalidArgumentException('Select a patient.');if($t<1)throw new InvalidArgumentException('Select a therapist.');if(!preg_match('/^\d{4}-\d{2}-\d{2}$/',$date))throw new InvalidArgumentException('Enter a valid appointment date.');if(!preg_match('/^\d{2}:\d{2}$/',$start)||!preg_match('/^\d{2}:\d{2}$/',$end)||$end<=$start)throw new InvalidArgumentException('Enter a valid start and end time.');if(!in_array($status,['scheduled','confirmed','completed','cancelled','no_show'],true))throw new InvalidArgumentException('Invalid appointment status.');$a=$this->appointments->activeAssignment($p,$t);if($a===null)throw new InvalidArgumentException('The therapist must have a current active assignment to this patient.');if($date<$a['assigned_at'])throw new InvalidArgumentException('Appointment date cannot be before the patient assignment start date.');return['patient_id'=>$p,'therapist_id'=>$t,'service_id'=>$s>0?$s:null,'appointment_date'=>$date,'start_time'=>$start,'end_time'=>$end,'status'=>$status,'notes'=>trim((string)($d['notes']??''))?:null];}
}
