<?php
/**
 * BookiFlex Background Jobs Extension
 *
 * @package    BookiFlex
 * @subpackage BackgroundJobs
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Extensions\BackgroundJobs\Service;

use BookiFlex\Core\Contract\PluginInterface;
use BookiFlex\Core\Infrastructure\Storage\CacheRepositoryInterface;
use Psr\Log\LoggerInterface;

defined( 'ABSPATH' ) || exit;

/**
 * Fallback Runner Service
 *
 * Provides a fallback mechanism to trigger ActionScheduler via shutdown hook.
 */
class FallbackRunner
{
    private const TRANSIENT_LOCK = 'bflex_bgj_fallback_lock';
    private const ENABLED = true;  // Hardcoded - always enabled
    private const INTERVAL_SECONDS = 300;  // 5 minutes

    public function __construct(
        private readonly QueueRunner $queueRunner,
        private readonly HealthChecker $healthChecker,
        private readonly CacheRepositoryInterface $cache,
        private readonly ?LoggerInterface $logger = null
    ) {
    }

    /**
     * Register the shutdown hook
     *
     * @param PluginInterface $plugin Plugin instance
     */
    public function register(PluginInterface $plugin): void
    {
        $plugin->addAction('shutdown', [$this, 'onShutdown']);
    }

    /**
     * Shutdown hook handler
     *
     * Triggers queue run if conditions are met and lock can be acquired.
     */
    public function onShutdown(): void
    {
        if (!$this->shouldRun()) {
            return;
        }

        try {
            // Acquire lock with hardcoded interval (5 minutes)
            if (!$this->acquireLock(self::INTERVAL_SECONDS)) {
                return;
            }

            // Run queue
            $this->queueRunner->run();

            // Record successful run
            $this->healthChecker->recordRun();
        } catch (\Throwable $e) {
            // Silent failure - don't break page load
            $this->logger?->error('BackgroundJobs FallbackRunner error', ['error' => $e->getMessage()]);
        }
    }

    /**
     * Check if fallback should run
     *
     * @return bool True if enabled and ActionScheduler is available
     */
    private function shouldRun(): bool
    {
        return self::ENABLED && $this->queueRunner->isAvailable();
    }

    /**
     * Acquire transient-based lock
     *
     * @param int $interval Lock TTL in seconds
     * @return bool True if lock acquired, false if already locked
     */
    private function acquireLock(int $interval): bool
    {
        if ($this->cache->has(self::TRANSIENT_LOCK)) {
            return false;
        }

        return $this->cache->set(self::TRANSIENT_LOCK, time(), $interval);
    }
}
