<?php

namespace App\Jobs;

use App\Models\JobPackage;
use App\Services\Matching\MatchingEngineService;
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;

/**
 * Job untuk proses matching
 *
 * This job will process matching for a specific package
 * and select the best contractor based on algorithm
 */
class ProcessMatchingJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Package ID to process
     */
    protected int $packageId;

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

    /**
     * Create a new job instance
     */
    public function __construct(int $packageId)
    {
        $this->packageId = $packageId;
        $this->onQueue('matching');
    }

    /**
     * Execute the job
     */
    public function handle(MatchingEngineService $matchingEngine): void
    {
        try {
            Log::info('Matching job started', ['package_id' => $this->packageId]);

            // 1. Get package
            $package = JobPackage::find($this->packageId);

            if (!$package) {
                Log::warning('Package not found for matching', ['package_id' => $this->packageId]);
                return;
            }

            // 2. Check if package can be matched
            if (!$package->canBeMatched()) {
                Log::info('Package already processed or not matchable', [
                    'package_id' => $this->packageId,
                    'status' => $package->status
                ]);
                return;
            }

            // 3. Process matching
            $result = $matchingEngine->process($package);

            // 4. Log result
            Log::info('Matching job completed', [
                'package_id' => $this->packageId,
                'result' => $result,
            ]);
        } catch (\Exception $e) {
            Log::error('Matching job failed', [
                'package_id' => $this->packageId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // Re-throw to trigger retry
            throw $e;
        }
    }

    /**
     * Handle job failure
     */
    public function failed(\Throwable $e): void
    {
        Log::critical('Matching job permanently failed', [
            'package_id' => $this->packageId,
            'error' => $e->getMessage(),
        ]);

        // Update package status back to active
        $package = JobPackage::find($this->packageId);
        if ($package && $package->status === JobPackage::STATUS_MATCHING) {
            $package->update(['status' => JobPackage::STATUS_ACTIVE]);
        }
    }
}