<?php

namespace App\Jobs;

use App\Http\Controllers\ClaudeAiController;
use App\Models\AiKeyword;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class ProcessKeywordJob implements ShouldQueue
{
	use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
	
	protected string $keyword;
	
	/**
	 * The number of times the job may be attempted.
	 */
	public int $tries;
	
	/**
	 * The maximum number of seconds the job can run.
	 */
	public int $timeout;
	
	/**
	 * Calculate the number of seconds to wait before retrying the job.
	 */
	public function backoff(): array
	{
		return config('anthropic.job_config.backoff', [10, 30, 60]);
	}
	
	/**
	 * Create a new job instance.
	 */
	public function __construct(string $keyword)
	{
		$this->keyword = $keyword;
		
		// Set configuration from config file
		$this->tries = config('anthropic.job_config.retries', 3);
		$this->timeout = config('anthropic.job_config.timeout', 300);
	}
	
	/**
	 * Execute the job.
	 */
	public function handle(): void
	{
		try {
			// Check if batch has been cancelled
			if ($this->batch()?->cancelled()) {
				return;
			}
			
			// Find the keyword in database
			$aiKeyword = AiKeyword::where('keyword', $this->keyword)->first();
			
			if (!$aiKeyword) {
				Log::error('ProcessKeywordJob: Keyword not found in database', [
					'keyword' => $this->keyword
				]);
				return;
			}
			
			// Call Claude AI to analyze the keyword
			$aiData = $this->callClaudeAI($this->keyword);
			
			// Update the keyword with AI analysis results
			$aiKeyword->update([
				'volume'   => $aiData['volume'],
				'intent'   => $aiData['intent'],
				'persona'  => $aiData['persona'],
				'priority' => $aiData['priority'],
				'status'   => 'completed',
			]);
		} catch (\Exception $e) {
			Log::error('ProcessKeywordJob failed', [
				'keyword'   => $this->keyword,
				'error'     => $e->getMessage(),
				'attempt'   => $this->attempts(),
				'max_tries' => $this->tries
			]);
			
			// If this is the final attempt, mark as failed
			if ($this->attempts() >= $this->tries) {
				AiKeyword::where('keyword', $this->keyword)
					->update(['status' => 'failed']);
				
				Log::error('ProcessKeywordJob permanently failed after all retries', [
					'keyword'        => $this->keyword,
					'final_error'    => $e->getMessage(),
					'total_attempts' => $this->attempts()
				]);
			}
			
			// Re-throw exception to trigger retry mechanism
			throw $e;
		}
	}
	
	/**
	 * Call Claude AI to analyze keyword
	 */
	private function callClaudeAI(string $keyword): array
	{
		$maxAttempts = 3;
		$attempt = 0;
		$lastException = null;
		
		while ($attempt < $maxAttempts) {
			$attempt++;
			
			try {
				// Build prompt for keyword analysis
				$prompt = "Analyze this keyword for SEO and content strategy: '{$keyword}'\n\n" .
					"Please provide the following information in JSON format:\n" .
					"{\n" .
					"  \"volume\": <estimated monthly search volume as integer>,\n" .
					"  \"intent\": \"<search intent: informational, commercial, transactional, or navigational>\",\n" .
					"  \"persona\": \"<target audience persona in 2-3 words>\",\n" .
					"  \"priority\": \"<priority level: high, medium, or low>\"\n" .
					"}\n\n" .
					"Only return valid JSON, no additional text.";
				
				// Use ClaudeAiController public method with extended timeout
				$claudeController = app(ClaudeAiController::class);
				$response = $claudeController->callAnthropicAPI([
					'max_tokens' => config('anthropic.max_tokens.keyword', 300),
					'messages'   => [
						['role' => 'user', 'content' => $prompt]
					]
				]);
				
				$aiResponse = $response['content'][0]['text'];
				
				// Parse JSON response
				preg_match('/\{.*\}/s', $aiResponse, $matches);
				if (empty($matches)) {
					throw new \Exception('Invalid AI response format: no JSON found in response');
				}
				
				$decoded = json_decode($matches[0], true);
				if (!$decoded) {
					throw new \Exception('Failed to parse AI response JSON: ' . json_last_error_msg());
				}
				
				$result = [
					'volume'   => (int)($decoded['volume'] ?? 0),
					'intent'   => $decoded['intent'] ?? null,
					'persona'  => $decoded['persona'] ?? null,
					'priority' => in_array($decoded['priority'] ?? '', ['high', 'medium', 'low'])
						? $decoded['priority']
						: 'medium',
				];
				
				return $result;
			} catch (\Exception $e) {
				$lastException = $e;
				$errorMessage = $e->getMessage();
				
				Log::warning('Claude AI analysis attempt failed', [
					'keyword'      => $keyword,
					'ai_attempt'   => $attempt,
					'max_attempts' => $maxAttempts,
					'error'        => $errorMessage
				]);
				
				// Check if this is a timeout or network error that we should retry
				$isRetryableError = stripos($errorMessage, 'timeout') !== false ||
					stripos($errorMessage, 'curl error') !== false ||
					stripos($errorMessage, 'overloaded') !== false ||
					stripos($errorMessage, '429') !== false ||
					stripos($errorMessage, '502') !== false ||
					stripos($errorMessage, '503') !== false;
				
				// If not retryable or last attempt, throw immediately
				if (!$isRetryableError || $attempt >= $maxAttempts) {
					break;
				}
				
				// Wait before retry (exponential backoff)
				$waitTime = min(pow(2, $attempt) * 5, 30); // 10s, 20s, 30s max
				Log::info("Retrying Claude AI analysis in {$waitTime} seconds", [
					'keyword'    => $keyword,
					'ai_attempt' => $attempt
				]);
				sleep($waitTime);
			}
		}
		
		// If we get here, all attempts failed
		Log::error('All Claude AI analysis attempts failed', [
			'keyword'        => $keyword,
			'total_attempts' => $attempt,
			'final_error'    => $lastException?->getMessage()
		]);
		
		// Instead of returning defaults, throw the exception to trigger job retry
		throw $lastException ?? new \Exception('Claude AI analysis failed after all attempts');
	}
}