<?php

namespace App\Command;

use App\Entity\Campaign\Schedule;
use App\Service\Campaign\ScheduleService;
use App\Service\CampaignService;
use DateTime;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class CrmRunScheduleCommand extends Command
{
    protected static $defaultName = 'crm:run:schedule';
    private $scheduleService;
    /**
     * @var CampaignService
     */
    private $campaignService;

    public function __construct(ScheduleService $scheduleService, CampaignService $campaignService, $name = null)
    {
        parent::__construct($name);
        $this->scheduleService = $scheduleService;
        $this->campaignService = $campaignService;
    }

    protected function configure()
    {
        $this
            ->setDescription('Run Campaign Schedules');
    }

    /**
     * @return void
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);

        $jobs = $this->scheduleService->getNotExecutedSchedulesFromToday();

        /** @var Schedule $job */
        foreach ($jobs as $job) {
            $commandName = $this->getCommandName($job);

            try {
                $command = $this->getApplication()->find($commandName);
                $arguments = $this->getCommandArguments($job);
            } catch (Exception $e) {
                $io->note(sprintf('Job: %s, Error: %s', $job->getId(), $e->getMessage()));

                continue;
            }

            $commandInput = new ArrayInput($arguments);
            $output = new BufferedOutput();

            try {
                $returnCode = $command->run($commandInput, $output);
                if (0 === $returnCode) {
                    $job->setOutput('OK');
                } else {
                    $job->setOutput(rtrim($output->fetch()));
                }
            } catch (Exception $e) {
                $job->setOutput($e->getMessage());
            }

            $job->setExecutedAt(new DateTime());
            $this->scheduleService->save($job);
        }
    }

    private function getCommandName(Schedule $job)
    {
        switch ($job->getType()) {
            case 'CONTENTS':
                return 'crm:make:content';

                break;
            case 'NEGOTIATIONS':
                return 'crm:make:negotiation';

                break;
            case 'RESEARCHES':
                return 'crm:make:research';

                break;
            case 'TASK_LISTS':
                return 'crm:clone:tasklist';

                break;
            case 'REPORTS':
                return 'crm:make:report';

                break;
            case 'ACTIONS':
                switch ($job->getOptions()['action']) {
                    case 'domainStats':
                        return 'crm:domain:check';

                        break;
                    case 'robots':
                        return 'crm:check:robots';

                        break;
                    case 'sitemap':
                        return 'crm:check:sitemap';

                        break;
                    case 'organicOverview':
                        return 'crm:check:organic';

                        break;
                    case 'pageSpeed':
                        return 'crm:check:speed';

                        break;
                    case 'onSite':
                    default:
                        return 'about';

                        break;
                }

                break;
            default:
                return 'about';

                break;
        }
    }

    private function getCommandArguments(Schedule $job)
    {
        switch ($job->getType()) {
            case 'CONTENTS':
                $type = array_key_exists('option', $job->getOptions()) ? $job->getOptions()['option'] : [];

                return [
                    'type' => $type['id'],
                    'campaign' => $job->getCampaign(),
                ];

                break;
            case 'TASK_LISTS':
                $tasklist = $job->getOptions()['option'];

                return [
                    'tasklist' => $tasklist,
                    'campaign' => $job->getCampaign(),
                ];

                break;
            case 'REPORTS':
                $preset = array_key_exists('option', $job->getOptions()) ? $job->getOptions()['option'] : null;

                return [
                    'campaign' => $job->getCampaign(),
                    'date' => $job->getExecuteAt()->format('Y-m-d h:i:s'),
                    'preset' => $preset['id'],
                ];

                break;
            case 'RESEARCHES':
                $contentType = array_key_exists('option', $job->getOptions()) ? $job->getOptions()['option'] : [];

                return [
                    'campaign' => $job->getCampaign(),
                    'contentType' => $contentType['id'],
                ];

                break;
            case 'ACTIONS':
                switch ($job->getOptions()['action']) {
                    case 'domainStats':
                        return [
                            'domainId' => $this->campaignService->getCampaign($job->getCampaign())->getDomain()->getId(),
                        ];

                        break;
                    case 'robots':
                        return [
                            'campaignId' => $this->campaignService->getCampaign($job->getCampaign())->getId(),
                        ];

                        break;
                    case 'sitemap':
                        return [
                            'campaignId' => $this->campaignService->getCampaign($job->getCampaign())->getId(),
                        ];

                        break;
                    case 'organicOverview':
                        return [
                            'campaignId' => $this->campaignService->getCampaign($job->getCampaign())->getId(),
                        ];

                        break;
                    case 'pageSpeed':
                        return [
                            'campaignId' => $this->campaignService->getCampaign($job->getCampaign())->getId(),
                        ];

                        break;
                    case 'onSite':
                    default:
                        return [];

                        break;
                }

                break;
            case 'NEGOTIATIONS':
            default:
                return [
                    'campaign' => $job->getCampaign(),
                ];
        }
    }
}
