<?php

declare(strict_types=1);

namespace App\Framework\Exception\Core;

use App\Framework\Exception\ErrorCode;

/**
 * Queue error codes
 *
 * Covers queue operations, job processing, and worker management
 */
enum QueueErrorCode: string implements ErrorCode
{
    case QUEUE_FULL = 'QUEUE001';
    case JOB_FAILED = 'QUEUE002';
    case JOB_TIMEOUT = 'QUEUE003';
    case WORKER_UNAVAILABLE = 'QUEUE004';
    case SERIALIZATION_FAILED = 'QUEUE005';
    case DEAD_LETTER_QUEUE_FULL = 'QUEUE006';
    case JOB_NOT_FOUND = 'QUEUE007';
    case CHAIN_NOT_FOUND = 'QUEUE008';
    case INVALID_STATE = 'QUEUE009';
    case CIRCULAR_DEPENDENCY = 'QUEUE010';

    public function getValue(): string
    {
        return $this->value;
    }

    public function getCategory(): string
    {
        return 'QUEUE';
    }

    public function getNumericCode(): int
    {
        return (int) substr($this->value, -3);
    }

    public function getSeverity(): ErrorSeverity
    {
        return match($this) {
            self::QUEUE_FULL,
            self::DEAD_LETTER_QUEUE_FULL => ErrorSeverity::CRITICAL,

            self::JOB_FAILED,
            self::WORKER_UNAVAILABLE,
            self::SERIALIZATION_FAILED,
            self::JOB_NOT_FOUND,
            self::CHAIN_NOT_FOUND,
            self::CIRCULAR_DEPENDENCY => ErrorSeverity::ERROR,

            self::JOB_TIMEOUT,
            self::INVALID_STATE => ErrorSeverity::WARNING,
        };
    }

    public function getDescription(): string
    {
        return match($this) {
            self::QUEUE_FULL => 'Queue is full and cannot accept new jobs',
            self::JOB_FAILED => 'Job execution failed',
            self::JOB_TIMEOUT => 'Job execution timed out',
            self::WORKER_UNAVAILABLE => 'No workers available to process job',
            self::SERIALIZATION_FAILED => 'Job serialization or deserialization failed',
            self::DEAD_LETTER_QUEUE_FULL => 'Dead letter queue is full',
            self::JOB_NOT_FOUND => 'Job not found in queue or persistence layer',
            self::CHAIN_NOT_FOUND => 'Job chain not found',
            self::INVALID_STATE => 'Operation not allowed in current state',
            self::CIRCULAR_DEPENDENCY => 'Circular dependency detected in job chain',
        };
    }

    public function getRecoveryHint(): string
    {
        return match($this) {
            self::QUEUE_FULL => 'Increase queue capacity or process existing jobs',
            self::JOB_FAILED => 'Review job logs and fix underlying issue',
            self::JOB_TIMEOUT => 'Increase job timeout or optimize job execution',
            self::WORKER_UNAVAILABLE => 'Start more workers or wait for availability',
            self::SERIALIZATION_FAILED => 'Check job payload and serialization format',
            self::DEAD_LETTER_QUEUE_FULL => 'Process or clear dead letter queue',
            self::JOB_NOT_FOUND => 'Verify job ID and check if job was already processed or expired',
            self::CHAIN_NOT_FOUND => 'Verify chain ID and check chain existence',
            self::INVALID_STATE => 'Check chain/job status and verify operation prerequisites',
            self::CIRCULAR_DEPENDENCY => 'Review job dependencies and remove circular references',
        };
    }

    public function isRecoverable(): bool
    {
        return match($this) {
            self::SERIALIZATION_FAILED => false,
            default => true,
        };
    }

    public function getRetryAfterSeconds(): ?int
    {
        return match($this) {
            self::QUEUE_FULL => 30,
            self::WORKER_UNAVAILABLE => 60,
            self::JOB_FAILED => 120,
            default => null,
        };
    }
}
