<?php

namespace PortalPeople\queues\jobs;

use Yii;
use yii\base\BaseObject;
use common\components\Queue\JobInterface;
use common\components\Queue\RetryableJobInterface;

/**
 * Recurring Job Wrapper
 * 
 * Wraps a job class and automatically re-queues it after execution
 * based on configured interval. Used by the module bootstrap to
 * create background recurring jobs.
 * 
 * @author Portal People
 */
class RecurringJobWrapper extends BaseObject implements JobInterface, RetryableJobInterface
{
    /**
     * @var string Fully qualified class name of the job to execute
     */
    public $jobClass;
    
    /**
     * @var array Job properties to set when instantiating
     */
    public $jobParams = [];
    
    /**
     * @var int Delay in seconds before re-queuing
     */
    public $interval = 3600;
    
    /**
     * @var string Queue component name (e.g., 'queue', 'mailqueue')
     */
    public $queueComponent = 'queue';
    
    /**
     * @var string Human-readable job name for tracking
     */
    public $jobName;
    
    /**
     * @var int Time-to-reserve in seconds
     */
    public $ttr = 300;
    
    /**
     * @var bool Whether this job should continue recurring
     */
    public $enabled = true;
    
    /**
     * @var int Maximum number of times to retry on failure
     */
    public $maxRetries = 3;
    
    /**
     * Execute the wrapped job and re-queue if enabled.
     * 
     * @param \common\components\Queue\Queue $queue
     * @return mixed
     */
    public function execute($queue)
    {
        try {
            // Instantiate the actual job
            if (!class_exists($this->jobClass)) {
                throw new \Exception("Job class {$this->jobClass} does not exist");
            }
            
            $job = Yii::createObject(array_merge(
                ['class' => $this->jobClass],
                $this->jobParams
            ));
            
            // Execute the job
            $result = $job->execute($queue);
            
            // Check if job implements RecurringJobInterface for dynamic control
            if ($job instanceof \PortalPeople\queues\RecurringJobInterface) {
                $shouldContinue = $job->shouldContinue();
                $nextInterval = $job->getRecurringInterval();
            } else {
                $shouldContinue = $this->enabled;
                $nextInterval = $this->interval;
            }
            
            // Re-queue if still enabled
            if ($shouldContinue) {
                $this->requeue($nextInterval);
            }
            
            return $result;
            
        } catch (\Exception $e) {
            Yii::error([
                'message' => 'Recurring job failed: ' . $e->getMessage(),
                'job' => $this->jobClass,
                'trace' => $e->getTraceAsString(),
            ], __METHOD__);
            
            // Still re-queue on failure (will retry via canRetry)
            if ($this->enabled) {
                $this->requeue($this->interval);
            }
            
            throw $e;
        }
    }
    
    /**
     * Re-queue this wrapper job for next execution.
     * 
     * @param int $delay Delay in seconds
     * @return void
     */
    protected function requeue($delay)
    {
        try {
            $queueComponent = Yii::$app->get($this->queueComponent);
            
            $queueComponent
                ->jobname($this->jobName ?: "Recurring: {$this->jobClass}")
                ->delay($delay)
                ->ttr($this->ttr)
                ->push(new self([
                    'jobClass' => $this->jobClass,
                    'jobParams' => $this->jobParams,
                    'interval' => $this->interval,
                    'queueComponent' => $this->queueComponent,
                    'jobName' => $this->jobName,
                    'ttr' => $this->ttr,
                    'enabled' => $this->enabled,
                    'maxRetries' => $this->maxRetries,
                ]));
                
        } catch (\Exception $e) {
            Yii::error([
                'message' => 'Failed to re-queue recurring job: ' . $e->getMessage(),
                'job' => $this->jobClass,
            ], __METHOD__);
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function getTtr()
    {
        return $this->ttr;
    }
    
    /**
     * {@inheritdoc}
     */
    public function canRetry($attempt, $error)
    {
        return $attempt < $this->maxRetries;
    }
}
