<?php

declare(strict_types=1);

class CronManager
{
    private PDO $pdo;

    private Lock $lock;

    private Logger $logger;

    public function __construct(PDO $pdo)
    {
        $this->pdo=$pdo;

        $this->lock=new Lock($pdo);

        $this->logger=new Logger($pdo);
    }

    public function run(): void
    {
        foreach ($this->discoverJobs() as $class){

            $job=new $class($this->pdo);

            $this->execute($job);

        }
    }

    private function discoverJobs(): array
    {
        $jobs=[];

        foreach (glob(dirname(__DIR__)."/Jobs/*Job.php") as $file){

            $jobs[]=basename($file,'.php');

        }

        return $jobs;
    }

    private function execute(Job $job): void
    {
        $name=$job->getName();

        $st=$this->pdo->prepare("
            SELECT *
            FROM cron_jobs
            WHERE name=?
            LIMIT 1
        ");

        $st->execute([$name]);

        $cron=$st->fetch(PDO::FETCH_ASSOC);

        if(!$cron)
            return;

        if(!$cron["enabled"])
            return;

        if(
            $cron["last_run"] &&
            strtotime($cron["last_run"])+$cron["interval_seconds"]>time()
        ){
            return;
        }

        if(!$this->lock->acquire($name))
            return;

        $started=microtime(true);

        try{

            $job->handle();

            $this->logger->log(
                $name,
                "success",
                "Completed",
                $started
            );

        }catch(Throwable $e){

            $this->logger->log(
                $name,
                "error",
                $e->getMessage(),
                $started
            );

            $this->logger->error($e);

        }finally{

            $this->lock->release($name);

        }
    }
}