<?php

namespace Openguru\OpenCartFramework\MaintenanceTasks;

use Carbon\Carbon;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Migrations\MigratorService;
use Psr\Log\LoggerInterface;

class MaintenanceTasksService
{
    private MigratorService $migrator;
    private LoggerInterface $logger;
    private CacheInterface $cache;
    private array $maintenanceTasks;

    public function __construct(
        MigratorService $migrator,
        LoggerInterface $logger,
        CacheInterface $cache,
        array $maintenanceTasks = []
    ) {
        $this->migrator = $migrator;
        $this->logger = $logger;
        $this->cache = $cache;
        $this->maintenanceTasks = $maintenanceTasks;
    }

    public function run(): void
    {
        $this->migrator->migrate();
        $this->performMaintenanceTasks();
    }

    private function performMaintenanceTasks(): void
    {
        foreach ($this->maintenanceTasks as $maintenanceTask) {
            /** @var MaintenanceTaskInterface $instance */
            $instance = $maintenanceTask();

            if ($this->shouldPerformTask($instance)) {
                $startTime = microtime(true);
                $instance->handle();
                $endTime = microtime(true);
                $this->logger->info(
                    sprintf(
                        'Maintenance task %s executed by %d seconds',
                        get_class($instance),
                        $endTime - $startTime
                    ),
                );
            }
        }
    }

    private function shouldPerformTask(MaintenanceTaskInterface $task): bool
    {
        $cacheKey = 'maintenance_tasks.' . md5(get_class($task));
        $lastExecuted = $this->cache->get($cacheKey);

        if (!$lastExecuted) {
            $this->cache->set($cacheKey, Carbon::now());
            return true;
        }

        $last = Carbon::parse($lastExecuted);
        $next = $last->copy()->add($task->interval());

        if (Carbon::now()->gte($next)) {
            $this->cache->set($cacheKey, Carbon::now());
            return true;
        }

        return false;
    }
}
