<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\ServiceRepository;
use InvalidArgumentException;
use RuntimeException;

final class ServiceService
{
    public function __construct(private ?ServiceRepository $repository = null)
    { $this->repository ??= new ServiceRepository(); }

    public function list(array $filters): array { return $this->repository->paginate($filters); }
    public function find(int $id): array
    { $row=$this->repository->find($id); if($row===null) throw new RuntimeException('Service not found.',404); return $row; }

    public function create(array $input, int $userId): int
    {
        $data=$this->validate($input);
        try { $id=$this->repository->create($data); $this->repository->audit($userId,'create', $id, ['name'=>$data['name']]); return $id; }
        catch (\PDOException $e) { if((string)$e->getCode()==='23000') throw new InvalidArgumentException('A service with this name already exists.'); throw $e; }
    }

    public function update(int $id,array $input,int $userId): void
    {
        $this->find($id); $data=$this->validate($input);
        try { $this->repository->update($id,$data); $this->repository->audit($userId,'update',$id,['name'=>$data['name']]); }
        catch (\PDOException $e) { if((string)$e->getCode()==='23000') throw new InvalidArgumentException('A service with this name already exists.'); throw $e; }
    }

    public function delete(int $id,int $userId): void
    {
        $this->find($id); $usage=$this->repository->usageCount($id);
        if($usage>0) throw new RuntimeException('This service is already used by '.$usage.' session(s). Deactivate it instead of deleting it.');
        $this->repository->delete($id); $this->repository->audit($userId,'delete',$id);
    }

    private function validate(array $input): array
    {
        $name=trim((string)($input['name']??''));
        if($name==='') throw new InvalidArgumentException('Service name is required.');
        if(mb_strlen($name)>190) throw new InvalidArgumentException('Service name is too long.');
        $price=(string)($input['price']??'0');
        if(!preg_match('/^\d+(?:\.\d{1,2})?$/',$price)) throw new InvalidArgumentException('Enter a valid price with up to 2 decimal places.');
        $status=(string)($input['status']??'active');
        if(!in_array($status,['active','inactive'],true)) throw new InvalidArgumentException('Invalid service status.');
        return ['name'=>$name,'description'=>trim((string)($input['description']??''))?:null,'price'=>number_format((float)$price,2,'.',''),'status'=>$status];
    }
}
