<?php

namespace App\Jobs;

use App\Models\ImageProcessingStatus;
use App\Services\GoogleImagenService;
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Exception;

class GenerateImagenBatch implements ShouldQueue
{
	use Queueable, InteractsWithQueue, SerializesModels, Batchable;
	
	public string $prompt;
	public int $sampleCount = 1;
	public string $imageId;
	public int $tries = 3; // Maximum retry attempts
	public int $backoff = 3; // Wait 3 seconds between retries
	
	/**
	 * Create a new job instance.
	 */
	public function __construct(string $imageId, string $prompt)
	{
		$this->imageId = $imageId;
		$this->prompt = $prompt;
	}
	
	/**
	 * Execute the job.
	 */
	public function handle(GoogleImagenService $imagenService): void
	{
		// Get actual batch and job IDs when job is running
		$batchJobId = $this->batch() ? $this->batch()->id : uniqid('batch_', true);
		$jobId = $this->job ? $this->job->getJobId() : uniqid('job_', true);
		
		// Validate prompt before processing
		if (empty(trim($this->prompt))) {
			Log::warning("Job skipped due to empty prompt", [
				'batch_id' => $batchJobId,
				'job_id'   => $jobId,
				'image_id' => $this->imageId
			]);
			return;
		}
		
		// Create or get existing processing status record
		$processingStatus = $this->getOrCreateProcessingStatus($batchJobId, $jobId);
		
		try {
			// Mark as processing
			$processingStatus->markAsProcessing();
			
			Log::info("Starting Imagen generation job", [
				'batch_id'     => $batchJobId,
				'job_id'       => $jobId,
				'image_id'     => $this->imageId,
				'prompt'       => $this->prompt,
				'sample_count' => $this->sampleCount,
				'attempt'      => $this->attempts()
			]);
			
			$startTime = microtime(true);
			$ratio = (str_contains($this->imageId, 'featured-')) ? '4:3' : '1:1';
			$images = $imagenService->generateImages($this->prompt, $this->sampleCount, $ratio);
			
			// Validate that we received images
			if (empty($images)) {
				throw new Exception("Google API returned 200 but no images were generated");
			}
			
			$endTime = microtime(true);
			$duration = round($endTime - $startTime, 2);
			
			// Save images to storage and verify files exist
			$savedImages = [];
			foreach ($images as $index => $image) {
				$filename = md5("{$batchJobId}_job{$this->imageId}_img{$index}_{$startTime}" . now()->timestamp) . ".png";
				$path = $imagenService->saveBase64Image($image['base64_data'], $filename);
				
				// Verify file was actually saved
				if (!Storage::disk('public')->exists($path)) {
					throw new Exception("Failed to save image file: {$filename}");
				}
				
				$fileSize = Storage::disk('public')->size($path);
				$savedImages[] = [
					'filename'  => $filename,
					'path'      => $path,
					'mime_type' => $image['mime_type'],
					'file_size' => $fileSize
				];
				
				// Update processing status for first image (main record)
				if ($index === 0) {
					$processingStatus->markAsCompleted($path, [
						'file_size'        => $fileSize,
						'mime_type'        => $image['mime_type'],
						'duration_seconds' => $duration,
						'total_images'     => count($images)
					]);
				}
			}
			
			Log::info("Imagen generation job completed", [
				'batch_id'         => $batchJobId,
				'job_id'           => $jobId,
				'image_id'         => $this->imageId,
				'prompt'           => $this->prompt,
				'images_generated' => count($images),
				'images_saved'     => count($savedImages),
				'duration_seconds' => $duration,
				'saved_files'      => $savedImages,
				'attempt'          => $this->attempts()
			]);
			
		} catch (Exception $e) {
			Log::error("Imagen generation job failed", [
				'batch_id'  => $batchJobId,
				'job_id'    => $jobId,
				'image_id'  => $this->imageId,
				'prompt'    => $this->prompt,
				'error'     => $e->getMessage(),
				'attempt'   => $this->attempts(),
				'max_tries' => $this->tries
			]);
			
			// Mark as failed in database
			$processingStatus->markAsFailed($e->getMessage());
			
			// Check if we should retry
			if ($this->attempts() < $this->tries) {
				$processingStatus->markAsRetrying();
				Log::info("Job will be retried", [
					'batch_id'  => $batchJobId,
					'job_id'    => $jobId,
					'image_id'  => $this->imageId,
					'attempt'   => $this->attempts(),
					'max_tries' => $this->tries
				]);
			}
			
			throw $e;
		}
	}
	
	/**
	 * Get or create processing status record
	 */
	private function getOrCreateProcessingStatus(?string $batchJobId, ?string $jobId): ImageProcessingStatus
	{
		return ImageProcessingStatus::firstOrCreate(
			[
				'batch_job_id' => $batchJobId,
				'job_id'       => $jobId
			],
			[
				'image_id'    => $this->imageId,
				'prompt'      => $this->prompt,
				'status'      => ImageProcessingStatus::STATUS_PENDING,
				'retry_count' => 0
			]
		);
	}
	
	/**
	 * Handle a job failure.
	 */
	public function failed(Exception $exception): void
	{
		// Get actual batch and job IDs when handling failure
		$batchJobId = $this->batch() ? $this->batch()->id : uniqid('batch_', true);
		$jobId = $this->job ? $this->job->getJobId() : uniqid('job_', true);
		
		Log::error("Imagen generation job failed permanently", [
			'batch_id' => $batchJobId,
			'job_id'   => $jobId,
			'image_id' => $this->imageId,
			'prompt'   => $this->prompt,
			'error'    => $exception->getMessage(),
			'attempts' => $this->attempts()
		]);
		
		// Update final failure status in database
		$processingStatus = $this->getOrCreateProcessingStatus($batchJobId, $jobId);
		$processingStatus->markAsFailed("Permanently failed after {$this->attempts()} attempts: " . $exception->getMessage());
	}
}
