<?php

declare(strict_types=1);
namespace App\Services;
use App\Repositories\TreatmentPlanRepository;
use InvalidArgumentException;
use RuntimeException;
final class TreatmentPlanService
{
    public function __construct(private ?TreatmentPlanRepository $plans=null){$this->plans??=new TreatmentPlanRepository();}
    public function list(array $filters,?int $therapistId=null):array{return $this->plans->paginate($filters,$therapistId,25);}
    public function find(int $id):array{$r=$this->plans->find($id);if($r===null)throw new RuntimeException('Treatment plan not found.',404);return $r;}
    public function formData(?int $therapistId=null):array{return ['patients'=>$therapistId!==null?$this->plans->patientsForTherapist($therapistId):$this->plans->allPatients(),'therapists'=>$therapistId!==null?array_values(array_filter($this->plans->therapists(),fn($t)=>(int)$t['id']===$therapistId)):$this->plans->therapists()];}
    public function create(array $d,int $actorId,?int $forcedTherapistId=null):int{$n=$this->validate($d,$forcedTherapistId);$id=$this->plans->create($n);$this->plans->audit($actorId,'treatment_plan_created',$id,['patient_id'=>$n['patient_id'],'therapist_id'=>$n['therapist_id']]);return $id;}
    public function update(int $id,array $d,int $actorId,?int $forcedTherapistId=null):void{$p=$this->find($id);$this->authorize($p,$forcedTherapistId);if($p['status']==='closed')throw new InvalidArgumentException('A closed treatment plan cannot be edited.');$n=$this->validate($d,$forcedTherapistId);$n['status']=$p['status'];$this->plans->update($id,$n);$this->plans->audit($actorId,'treatment_plan_updated',$id,['patient_id'=>$n['patient_id'],'therapist_id'=>$n['therapist_id']]);}
    public function setStatus(int $id,string $status,int $actorId,?int $therapistId=null):void{$p=$this->find($id);$this->authorize($p,$therapistId);if(!in_array($status,['active','completed','closed'],true))throw new InvalidArgumentException('Invalid treatment plan status.');if($therapistId!==null&&$status==='closed')throw new RuntimeException('Therapists cannot close treatment plans.',403);$this->plans->setStatus($id,$status);$this->plans->audit($actorId,'treatment_plan_status_changed',$id,['status'=>$status]);}
    public function canTherapistAccess(array $p,int $tid):bool{return (int)$p['therapist_id']===$tid&&$this->plans->activeAssignment((int)$p['patient_id'],$tid)!==null;}
    private function authorize(array $p,?int $tid):void{if($tid!==null&&!$this->canTherapistAccess($p,$tid))throw new RuntimeException('You do not have permission to access this treatment plan.',403);}
    private function validate(array $d,?int $forced):array{$patient=(int)($d['patient_id']??0);$therapist=$forced??(int)($d['therapist_id']??0);if($patient<1)throw new InvalidArgumentException('Select a patient.');if($therapist<1)throw new InvalidArgumentException('Select a therapist.');$a=$this->plans->activeAssignment($patient,$therapist);if($a===null)throw new InvalidArgumentException('The therapist must have a current active assignment to this patient.');$review=trim((string)($d['review_date']??''));if($review!==''&&!preg_match('/^\d{4}-\d{2}-\d{2}$/',$review))throw new InvalidArgumentException('Enter a valid review date.');$out=['patient_id'=>$patient,'therapist_id'=>$therapist,'assignment_id'=>(int)$a['id'],'goals'=>$this->txt($d,'goals'),'short_term_goals'=>$this->txt($d,'short_term_goals'),'long_term_goals'=>$this->txt($d,'long_term_goals'),'interventions'=>$this->txt($d,'interventions'),'frequency'=>$this->txt($d,'frequency'),'review_date'=>$review!==''?$review:null,'recommendations'=>$this->txt($d,'recommendations'),'status'=>'draft'];return $out;}
    private function txt(array $d,string $k):?string{$v=trim((string)($d[$k]??''));return $v===''?null:$v;}
}
