<?php

require_once __DIR__ . '/../config/database.php';

class QueueService
{
    public static function push(string $jobType, array $payload = [], string $queueName = 'default', int $delaySeconds = 0, int $maxAttempts = 3): bool
    {
        try {
            $availableAt = date('Y-m-d H:i:s', time() + $delaySeconds);

            db()->prepare("
                INSERT INTO job_queue
                    (queue_name, job_type, payload, status, attempts, max_attempts, available_at, created_at, updated_at)
                VALUES
                    (?, ?, ?, 'pending', 0, ?, ?, NOW(), NOW())
            ")->execute([
                $queueName,
                $jobType,
                json_encode($payload),
                $maxAttempts,
                $availableAt
            ]);

            return true;
        } catch (Throwable $e) {
            return false;
        }
    }

    public static function reserve(string $queueName = 'default'): ?array
    {
        try {
            db()->beginTransaction();

            $stmt = db()->prepare("
                SELECT *
                FROM job_queue
                WHERE queue_name = ?
                  AND status = 'pending'
                  AND available_at <= NOW()
                ORDER BY id ASC
                LIMIT 1
                FOR UPDATE
            ");
            $stmt->execute([$queueName]);
            $job = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$job) {
                db()->commit();
                return null;
            }

            db()->prepare("
                UPDATE job_queue
                SET status = 'processing',
                    attempts = attempts + 1,
                    started_at = NOW(),
                    updated_at = NOW()
                WHERE id = ?
            ")->execute([(int)$job['id']]);

            db()->commit();

            $job['payload_array'] = json_decode($job['payload'] ?: '{}', true) ?: [];

            return $job;
        } catch (Throwable $e) {
            if (db()->inTransaction()) {
                db()->rollBack();
            }

            return null;
        }
    }

    public static function complete(int $jobId): void
    {
        db()->prepare("
            UPDATE job_queue
            SET status = 'completed',
                finished_at = NOW(),
                updated_at = NOW()
            WHERE id = ?
        ")->execute([$jobId]);
    }

    public static function fail(array $job, string $error): void
    {
        $attempts = (int)($job['attempts'] ?? 0);
        $maxAttempts = (int)($job['max_attempts'] ?? 3);
        $jobId = (int)$job['id'];

        if ($attempts >= $maxAttempts) {
            db()->prepare("
                UPDATE job_queue
                SET status = 'failed',
                    last_error = ?,
                    finished_at = NOW(),
                    updated_at = NOW()
                WHERE id = ?
            ")->execute([$error, $jobId]);
        } else {
            db()->prepare("
                UPDATE job_queue
                SET status = 'pending',
                    last_error = ?,
                    available_at = DATE_ADD(NOW(), INTERVAL 2 MINUTE),
                    updated_at = NOW()
                WHERE id = ?
            ")->execute([$error, $jobId]);
        }
    }
}
