<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\AssessmentRepository;
use InvalidArgumentException;
use RuntimeException;

final class AssessmentService
{
    public function __construct(private ?AssessmentRepository $assessments=null){$this->assessments??=new AssessmentRepository();}
    public function list(array $filters,?int $therapistId=null):array{return $this->assessments->paginate($filters,$therapistId,25);}
    public function find(int $id):array{$row=$this->assessments->find($id);if($row===null)throw new RuntimeException('Assessment not found.',404);return $row;}
    public function formData(?int $therapistId=null):array{return ['patients'=>$therapistId!==null?$this->assessments->patientsForTherapist($therapistId):$this->assessments->allPatients(),'therapists'=>$therapistId!==null?array_values(array_filter($this->assessments->therapists(),fn($t)=>(int)$t['id']===$therapistId)):$this->assessments->therapists(),'services'=>$this->assessments->services()];}
    public function create(array $d,int $actorId,?int $forcedTherapistId=null):int{$n=$this->validate($d,$forcedTherapistId);$n['assessment_reference']=$this->assessments->nextReference();$n['status']='draft';$id=$this->assessments->create($n);$this->assessments->audit($actorId,'assessment_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{$a=$this->find($id);if(in_array($a['status'],['approved'],true))throw new InvalidArgumentException('An approved assessment cannot be edited.');if($forcedTherapistId!==null && $a['status']!=='draft')throw new InvalidArgumentException('A submitted assessment cannot be edited by a therapist.');$n=$this->validate($d,$forcedTherapistId);$this->assessments->update($id,$n);$this->assessments->audit($actorId,'assessment_updated',$id,['patient_id'=>$n['patient_id'],'therapist_id'=>$n['therapist_id']]);}
    public function submit(int $id,int $actorId,?int $therapistId=null):void{$a=$this->find($id);$this->authorizeTherapist($a,$therapistId);if(!in_array($a['status'],['draft'],true))throw new InvalidArgumentException('Only draft assessments can be submitted.');$this->assessments->setStatus($id,'submitted','submitted_at');$this->assessments->audit($actorId,'assessment_submitted',$id);}
    public function review(int $id,int $actorId):void{$a=$this->find($id);if($a['status']!=='submitted')throw new InvalidArgumentException('Only submitted assessments can be reviewed.');$this->assessments->setStatus($id,'reviewed','reviewed_at');$this->assessments->audit($actorId,'assessment_reviewed',$id);}
    public function approve(int $id,int $actorId):void{$a=$this->find($id);if($a['status']!=='reviewed')throw new InvalidArgumentException('Only reviewed assessments can be approved.');$this->assessments->setStatus($id,'approved','approved_at');$this->assessments->audit($actorId,'assessment_approved',$id);}
    public function billableAssessments(int $patientId): array{return $this->assessments->billableAssessments($patientId);}

    public function canTherapistAccess(array $a,int $therapistId):bool{return (int)$a['therapist_id']===$therapistId && $this->assessments->activeAssignment((int)$a['patient_id'],$therapistId)!==null;}
    private function authorizeTherapist(array $a,?int $therapistId):void{if($therapistId!==null&&!$this->canTherapistAccess($a,$therapistId))throw new RuntimeException('You do not have permission to access this assessment.',403);}
    private function validate(array $d,?int $forcedTherapistId=null):array{
        $patientId=(int)($d['patient_id']??0);$therapistId=$forcedTherapistId??(int)($d['therapist_id']??0);
        $serviceId=(int)($d['service_id']??0);
        if($serviceId<1) throw new InvalidArgumentException('Select the assessment service. All completed assessments are billable.');if($patientId<1)throw new InvalidArgumentException('Select a patient.');if($therapistId<1)throw new InvalidArgumentException('Select a therapist.');$date=trim((string)($d['assessment_date']??''));if(!preg_match('/^\d{4}-\d{2}-\d{2}$/',$date))throw new InvalidArgumentException('Enter a valid assessment date.');$assignment=$this->assessments->activeAssignment($patientId,$therapistId);if($assignment===null)throw new InvalidArgumentException('The therapist must have a current active assignment to this patient.');if($date<$assignment['assigned_at'])throw new InvalidArgumentException('Assessment date cannot be before the assignment start date.');
        $out=['patient_id'=>$patientId,'therapist_id'=>$therapistId,'assignment_id'=>(int)$assignment['id'],'service_id'=>$serviceId,'assessment_date'=>$date];foreach(['reason_for_referral','background','observations','clinical_findings','goals','recommendations','additional_notes'] as $f)$out[$f]=trim((string)($d[$f]??''))?:null;return $out;
    }
}
