<?php

declare(strict_types=1);

namespace Instinctor\Core;


if (!defined('ABSPATH')) exit;
use Instinctor\Core\Queue\DriverInterface;
use Instinctor\Core\Queue\DatabaseDriver;
use Instinctor\Core\Queue\WordPressDriver;
use Instinctor\Core\Queue\StandaloneDriver;

/**
 * Queue — static facade over the active job queue driver.
 *
 * Driver selection:
 *   INSTINCTOR_ENV = 'wordpress'   → WordPressDriver  (instinctor_jobs + WP-cron runner)
 *   INSTINCTOR_ENV = 'standalone'  → StandaloneDriver (instinctor_jobs + system cron runner)
 *
 * Both drivers use the same DatabaseDriver base — all job logic is shared.
 * The only difference is how the runner is triggered.
 *
 * ── Dispatch jobs ────────────────────────────────────────────────────────────
 *
 *   // Fire immediately
 *   Queue::dispatch('email', ['to' => $email, 'subject' => $subject, 'body' => $html]);
 *
 *   // Delay by 5 minutes
 *   Queue::dispatch('sms', ['to' => '+1555...', 'message' => 'Your order shipped'], 300);
 *
 *   // Webhook
 *   Queue::dispatch('webhook', ['url' => 'https://...', 'data' => $payload]);
 *
 * ── Built-in job types ───────────────────────────────────────────────────────
 *   'email'          — sends via Mailer::send() — payload: {to, subject, body, options[]}
 *   'sms'            — sends via relay SMS endpoint — payload: {to, message, channel}
 *   'webhook'        — HTTP POST/PUT/GET — payload: {url, data[], method, headers[]}
 *
 * ── Custom job types ─────────────────────────────────────────────────────────
 *   Queue::register('price_change', function(array $payload): bool {
 *       // apply scheduled price change
 *       return true;
 *   });
 *
 * ── Runner ───────────────────────────────────────────────────────────────────
 *   Queue::run()          // process up to 50 pending jobs
 *   Queue::run(200)       // process up to 200 jobs
 *
 * ── Monitoring ───────────────────────────────────────────────────────────────
 *   Queue::stats()        // ['pending' => N, 'running' => N, 'completed' => N, 'failed' => N]
 *   Queue::prune(7)       // delete completed/failed jobs older than 7 days
 */
class Queue
{
    private static ?DriverInterface $driver = null;

    public static function driver(): DriverInterface
    {
        if (self::$driver === null) {
            self::$driver = self::makeDriver();
        }
        return self::$driver;
    }

    public static function setDriver(DriverInterface $driver): void
    {
        self::$driver = $driver;
    }

    private static function makeDriver(): DriverInterface
    {
        $env = defined('INSTINCTOR_ENV') ? INSTINCTOR_ENV : 'wordpress';
        return match ($env) {
            'standalone' => new StandaloneDriver(),
            default      => new WordPressDriver(),
        };
    }

    // -------------------------------------------------------------------------
    // Static API
    // -------------------------------------------------------------------------

    /**
     * Dispatch a job to the queue.
     *
     * @param string $type    Job type: 'email', 'sms', 'webhook', or custom
     * @param array  $payload Job data
     * @param int    $delay   Seconds before job becomes available (0 = immediately)
     * @return int            Inserted job ID
     */
    public static function dispatch(string $type, array $payload, int $delay = 0): int
    {
        return self::driver()->dispatch($type, $payload, $delay);
    }

    /**
     * Process pending jobs.
     *
     * @param int $limit Max jobs to process in this run
     * @return int       Number of jobs processed
     */
    public static function run(int $limit = 50): int
    {
        return self::driver()->run($limit);
    }

    /**
     * Register a custom job handler.
     *
     * @param string   $type    Job type identifier
     * @param callable $handler Receives array $payload, must return bool
     */
    public static function register(string $type, callable $handler): void
    {
        DatabaseDriver::register($type, $handler);
    }

    /**
     * Get queue statistics.
     *
     * @return array{pending: int, running: int, completed: int, failed: int}
     */
    public static function stats(): array
    {
        return self::driver()->stats();
    }

    /**
     * Delete old completed and failed jobs.
     *
     * @param int $days Jobs older than this many days are deleted
     * @return int      Number of rows deleted
     */
    public static function prune(int $days = 7): int
    {
        return self::driver()->prune($days);
    }
}
