<?php

namespace think\queue\command;

use stdClass;
use think\console\Command;
use think\console\input\Argument;
use think\helper\Arr;

class Retry extends Command
{
    protected function configure()
    {
        $this->setName('queue:retry')
            ->addArgument('id', Argument::IS_ARRAY | Argument::REQUIRED, 'The ID of the failed job or "all" to retry all jobs')
            ->setDescription('Retry a failed queue job');
    }

    public function handle()
    {
        foreach ($this->getJobIds() as $id) {
            $job = $this->app['queue.failer']->find($id);

            if (is_null($job)) {
                $this->output->error("Unable to find failed job with ID [{$id}].");
            } else {
                $this->retryJob($job);

                $this->output->info("The failed job [{$id}] has been pushed back onto the queue!");

                $this->app['queue.failer']->forget($id);
            }
        }
    }

    /**
     * Retry the queue job.
     *
     * @param stdClass $job
     * @return void
     */
    protected function retryJob($job)
    {
        $this->app['queue']->connection($job['connection'])->pushRaw(
            $this->resetAttempts($job['payload']),
            $job['queue']
        );
    }

    /**
     * Reset the payload attempts.
     *
     * Applicable to Redis jobs which store attempts in their payload.
     *
     * @param string $payload
     * @return string
     */
    protected function resetAttempts($payload)
    {
        $payload = json_decode($payload, true);

        if (isset($payload['attempts'])) {
            $payload['attempts'] = 0;
        }

        return json_encode($payload);
    }

    /**
     * Get the job IDs to be retried.
     *
     * @return array
     */
    protected function getJobIds()
    {
        $ids = (array) $this->input->getArgument('id');

        if (count($ids) === 1 && $ids[0] === 'all') {
            $ids = Arr::pluck($this->app['queue.failer']->all(), 'id');
        }

        return $ids;
    }
}
