<?php

namespace App\Jobs;

use App\Models\Setting;
use App\Models\Video;
use FFMpeg\FFMpeg;
use FFMpeg\Format\Video\X264;
use Illuminate\Support\Facades\Config;
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;
use Illuminate\Support\Facades\Storage;

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

    public $video;

    public function __construct(Video $video)
    {
        $this->video = $video;
    }

    public function handle()
    {
        $video = $this->video;

        // Get original file path
        $originalPath = storage_path('app/' . $video->path);

        if (!file_exists($originalPath)) {
            Log::error('CompressVideoJob: Original file not found: ' . $originalPath);
            return;
        }

        // Create compressed file alongside the original
        $compressedFilename = 'compressed_' . $video->filename;
        $compressedPath = dirname($originalPath) . '/' . $compressedFilename;

        try {
            $ffmpegConfig = Config::get('ffmpeg');
            $ffmpeg = FFMpeg::create([
                'ffmpeg.binaries'  => $ffmpegConfig['ffmpeg']  ?? '/usr/bin/ffmpeg',
                'ffprobe.binaries' => $ffmpegConfig['ffprobe'] ?? '/usr/bin/ffprobe',
                'timeout'          => $ffmpegConfig['timeout']  ?? 3600,
            ]);
            $ffmpegVideo = $ffmpeg->open($originalPath);

            // Verify the GPU is actually reachable and able to encode before sending
            // the file to it; otherwise fall back to CPU so the job never hangs.
            $gpuEnabled = Setting::gpuUsable();
            $encoder    = Setting::gpuEncoder();
            $preset     = Setting::gpuPreset();
            $device     = Setting::gpuDevice();

            if ($gpuEnabled) {
                $videoPasses = [
                    "-c:v {$encoder}",
                    "-preset {$preset}",
                    '-rc vbr',
                    '-cq 23',
                    '-profile:v high',
                    '-pix_fmt yuv420p',
                    "-gpu {$device}",
                ];
            } else {
                $videoPasses = [
                    '-c:v libx264',
                    '-preset fast',
                    '-crf 23',
                    '-profile:v high',
                    '-pix_fmt yuv420p',
                ];
            }
            $audioPasses = ['-c:a aac', '-b:a 192k'];

            $format = new X264('aac', $encoder);
            foreach ($videoPasses as $pass) {
                $format->addLegacyOption($pass);
            }
            foreach ($audioPasses as $pass) {
                $format->addLegacyOption($pass);
            }
            $ffmpegVideo->save($format, $compressedPath);

            // Check if compressed file was created and is smaller
            if (file_exists($compressedPath)) {
                $originalSize = filesize($originalPath);
                $compressedSize = filesize($compressedPath);

                // Only use compressed file if it's smaller
                if ($compressedSize < $originalSize) {
                    // Delete original and rename compressed
                    unlink($originalPath);
                    rename($compressedPath, $originalPath);

                    // Update video record
                    $video->update([
                        'size' => $compressedSize,
                        'filename' => $video->filename, // Keep same filename
                        'mime_type' => 'video/mp4',
                    ]);

            Log::info('CompressVideoJob: Video compressed', [
                        'video_id' => $video->id,
                        'original_size' => $originalSize,
                        'compressed_size' => $compressedSize,
                        'saved' => round(($originalSize - $compressedSize) / $originalSize * 100) . '%',
                        'encoder' => $encoder,
                        'gpu' => $gpuEnabled,
                    ]);
                } else {
                    // Compressed file is larger, delete it
                    unlink($compressedPath);
                    Log::info('CompressVideoJob: Compression made file larger, keeping original');
                }
            }

            $video->update(['status' => 'ready']);

            // Chain to HLS generation for GPU-accelerated adaptive playback
            \App\Jobs\GenerateHlsJob::dispatch($video);

        } catch (\Exception $e) {
            Log::error('CompressVideoJob failed: ' . $e->getMessage());
            $video->update(['status' => 'ready']); // Mark as ready anyway
        }
    }
}

