<?php

namespace App\Modules\ThreeCX\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Modules\ThreeCX\Services\ThreeCXCallQueueService;
use Illuminate\Support\Facades\Log;

class ProcessThreeCXCall implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 3;

    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 120;

    /**
     * The call log ID to process
     *
     * @var int
     */
    protected $callLogId;

    /**
     * Create a new job instance.
     *
     * @param int $callLogId
     */
    public function __construct(int $callLogId)
    {
        $this->callLogId = $callLogId;
    }

    /**
     * Execute the job.
     *
     * @param ThreeCXCallQueueService $queueService
     * @return void
     */
    public function handle(ThreeCXCallQueueService $queueService)
    {
        Log::info('[3CX Job] Processing queued call', ['call_log_id' => $this->callLogId]);
        
        $result = $queueService->processQueuedCall($this->callLogId);
        
        if (!$result['success']) {
            Log::error('[3CX Job] Call processing failed', [
                'call_log_id' => $this->callLogId,
                'error' => $result['error'] ?? 'Unknown error',
                'attempt' => $this->attempts()
            ]);
            
            // If this is not the last attempt, the job will be retried
            if ($this->attempts() < $this->tries) {
                // Release the job back to the queue with exponential backoff
                $this->release($this->attempts() * 60);
            } else {
                // Final attempt failed, mark as permanently failed
                $this->fail(new \Exception($result['error'] ?? 'Call processing failed after all attempts'));
            }
        }
    }

    /**
     * Handle a job failure.
     *
     * @param \Throwable $exception
     * @return void
     */
    public function failed(\Throwable $exception)
    {
        Log::error('[3CX Job] Job failed permanently', [
            'call_log_id' => $this->callLogId,
            'error' => $exception->getMessage(),
            'trace' => $exception->getTraceAsString()
        ]);
        
        // Update the call log to reflect permanent failure
        try {
            $callLog = \App\Modules\ThreeCX\Models\TaskCallLog::find($this->callLogId);
            if ($callLog) {
                $callLog->update([
                    'status' => 'failed',
                    'metadata' => array_merge($callLog->metadata ?? [], [
                        'job_failed' => true,
                        'failure_reason' => $exception->getMessage(),
                        'failed_at' => now()->toIso8601String()
                    ])
                ]);
            }
        } catch (\Exception $e) {
            Log::error('[3CX Job] Failed to update call log after job failure', [
                'call_log_id' => $this->callLogId,
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * Calculate the number of seconds to wait before retrying the job.
     *
     * @return array
     */
    public function backoff()
    {
        return [60, 120, 300]; // 1 minute, 2 minutes, 5 minutes
    }
}