<?php

namespace App\Jobs;

use App\Models\File;
use App\Services\Files\FileStorageService;
use App\Services\Files\VirusScanService;
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 ScanFileForVirusJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

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

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

    /**
     * Create a new job instance.
     */
    public function __construct(
        protected File $file
    ) {
        $this->onQueue('virus-scan');
    }

    /**
     * Execute the job.
     */
    public function handle(
        FileStorageService $storageService,
        VirusScanService $virusScanService
    ): void {
        // Refresh the model
        $this->file->refresh();

        // Check if file still exists
        if (! $this->file->exists()) {
            return;
        }

        // Check if scanner is available
        if (! $virusScanService->isAvailable()) {
            Log::info('Virus scanner not available, skipping scan', [
                'file_id' => $this->file->id,
            ]);

            $this->file->update([
                'virus_scan_status' => 'skipped',
                'virus_scanned_at' => now(),
            ]);

            return;
        }

        try {
            // Download file to temp location for scanning
            $tempPath = tempnam(sys_get_temp_dir(), 'scan_');
            file_put_contents($tempPath, $storageService->get($this->file->path));

            // Perform scan
            $result = $virusScanService->scan($tempPath);

            // Clean up temp file
            unlink($tempPath);

            if ($result === 'clean') {
                $this->file->update([
                    'virus_scan_status' => 'clean',
                    'virus_scanned_at' => now(),
                ]);

                Log::info('File scanned successfully - clean', [
                    'file_id' => $this->file->id,
                ]);
            } elseif ($result === 'infected') {
                $this->file->update([
                    'virus_scan_status' => 'infected',
                    'virus_scanned_at' => now(),
                ]);

                // Quarantine the file
                $quarantinePath = $storageService->quarantine($this->file);
                $this->file->update(['path' => $quarantinePath]);

                Log::warning('File infected and quarantined', [
                    'file_id' => $this->file->id,
                ]);

                // Notify admins (could dispatch an event here)
                // event(new VirusDetected($this->file));
            }
        } catch (\Exception $e) {
            Log::error('Virus scan failed', [
                'file_id' => $this->file->id,
                'error' => $e->getMessage(),
            ]);

            $this->file->update([
                'virus_scan_status' => 'skipped',
                'virus_scanned_at' => now(),
            ]);

            throw $e;
        }
    }

    /**
     * Handle a job failure.
     */
    public function failed(\Throwable $exception): void
    {
        Log::error('Virus scan job failed', [
            'file_id' => $this->file->id,
            'error' => $exception->getMessage(),
        ]);

        $this->file->update([
            'virus_scan_status' => 'skipped',
            'virus_scanned_at' => now(),
        ]);
    }
}
