<?php

namespace FiloBlu\Flow\Console\Command;

use Exception;
use FiloBlu\Flow\Cron\FetchFactory;
use Magento\Framework\App\State;
use Magento\Framework\Exception\LocalizedException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Throwable;

/**
 * Class CriticalCommand
 * @package FiloBlu\Flow\Console\Command
 */
class CycleCommand extends BaseCommand
{
    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * CycleCommand constructor.
     * @param State $state
     * @param FetchFactory $fetchFactory
     * @param LoggerInterface $logger
     * @param null $name
     */
    public function __construct(
        State $state,
        FetchFactory $fetchFactory,
        LoggerInterface $logger,
        $name = null
    ) {
        $this->logger = $logger;
        parent::__construct($state, $fetchFactory, $name);
    }

    /**
     *
     */
    protected function configure()
    {
        $this->setName('flow:cycle')
            ->setDescription('Execute fetch, receive, parse and process at once');
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int
     * @throws LocalizedException
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->ensureAreaCode($output);

        $cronModel = $this->fetchFactory->create();

        foreach ([1, 2, 3, 4] as $bus) {
            $output->write("Fetching bus {$bus} ... ");
            $this->executeMethod($cronModel, "executeBus{$bus}", $output);
        }

        $output->write('Receiving ... ');
        $this->executeMethod($cronModel, 'receive', $output);

        $output->write('Parsing ... ');
        $this->executeMethod($cronModel, 'parse', $output);

        $output->write('Processing ... ');
        $this->executeMethod($cronModel, 'process', $output);

        return 0;
    }

    /**
     * @param $subject
     * @param string $method
     * @param OutputInterface $output
     */
    protected function executeMethod($subject, $method, OutputInterface $output)
    {
        try {
            $subject->$method();
            $output->writeln('<info>done</info>');
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage(), ['exception' => $exception]);
            $output->writeln('<info>failed</info>');
        } catch (Throwable $throwable) {
            $this->logger->error($throwable->getMessage(), ['exception' => $throwable]);
            $output->writeln('<info>failed</info>');
        }
    }
}
