<?php

namespace Comitium5\DesignerBundle\Publisher\Worker;

use Comitium5\ApiClientBundle\Client\Client;
use Comitium5\DesignerBundle\Helper\MultiServerHelper;
use Comitium5\DesignerBundle\Helper\Process;
use Comitium5\DesignerBundle\Model\Interfaces\Page\PageInterface;
use Comitium5\DesignerBundle\Model\Traits\UserTokenDependencyTrait;
use Comitium5\DesignerBundle\Provider\SubsiteProvider;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Class PageAfterPublication
 *
 * @author Carles Gómez <carles@bab-soft.com>
 * @package Comitium5\DesignerBundle\Publisher\Worker
 */
class PageAfterPublication
{
    use UserTokenDependencyTrait;

    const CONSOLE = "app/console";

    /**
     * @var PageInterface[]
     */
    protected $pages;

    /**
     * @var string
     */
    protected $rootPath;

    /**
     * @var SubsiteProvider
     */
    private $subSiteProvider;

    /**
     * @var bool
     */
    protected $isRunningAsMultiServers;

    /**
     * @var MultiServerHelper
     */
    private $multiServerHelper;

    /**
     * @var Client
     */
    private $apiClient;

    /**
     * @var string
     */
    private $environment;

    /**
     * PageAfterPublication constructor.
     *
     * @param SubsiteProvider $subSiteProvider
     * @param string $rootPath
     * @param bool $isRunningAsMultiServers
     * @param MultiServerHelper $multiServerHelper
     * @param TokenStorageInterface $tokenStorage
     * @param Client $apiClient
     * @param string $environment
     */
    public function __construct(
        SubSiteProvider $subSiteProvider,
        string $rootPath,
        bool $isRunningAsMultiServers,
        MultiServerHelper $multiServerHelper,
        TokenStorageInterface $tokenStorage,
        Client $apiClient,
        string $environment
    ) {
        $this->subSiteProvider = $subSiteProvider;
        $this->rootPath = $rootPath;
        $this->isRunningAsMultiServers = $isRunningAsMultiServers;
        $this->multiServerHelper = $multiServerHelper;
        $this->tokenStorage = $tokenStorage;
        $this->apiClient = $apiClient;
        $this->environment = $environment;
    }


    /**
     * @param PageInterface
     *
     * @return $this
     */
    public function addPage($page)
    {
        $this->pages[] = $page;

        return $this;
    }

    /**
     * @param PageInterface[] $pages
     *
     * @return $this
     */
    public function setPages(array $pages)
    {
        $this->pages = $pages;

        return $this;
    }

    /**
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function work()
    {
        if (empty($this->pages)) {
            throw new \Exception("Pages must be defined");
        }

        $commands = $this->parseCommands($this->buildCommands());

        $process = new Process();
        $process->run($commands);
        $this->notify();
    }

    /**
     * @return array
     */
    private function buildCommands()
    {
        $commands = [];

        if ($this->isRunningAsMultiServers === false) {
            $commands[] = $this->command("cache:clear", sprintf("--env=%s --no-warmup", $this->environment));
            $commands[] = $this->command("cache:warmup", sprintf("--env=%s --no-optional-warmers", $this->environment));
        }
// @TODO This is an implementation for Teradisk servers which needs a replication
//        else {
//            $commands[] = $this
//                ->multiServerHelper
//                ->buildExecutionLine(
//                    implode(',', $this->frontPathsToAppConsole),
//                    MultiServerHelper::USE_CASE_PAGE
//                );
//        }

        return $commands;

    }

    /**
     * @param $command
     * @param $args
     *
     * @return string
     */
    private function command($command, $args)
    {
        $appConsole = $this->rootPath.DIRECTORY_SEPARATOR."console";

        return sprintf("(%s %s %s)",$appConsole, $command, $args);
    }

    /**
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function notify()
    {
        foreach ($this->pagesIds() as $pageId) {
            $this
                ->apiClient
                ->post(
                    'notify/page-sync-done',
                    [
                        'page_id' => $pageId
                    ]
                );
        }
    }

    /**
     * @return array
     */
    private function pagesIds(): array
    {
        return array_map(function (PageInterface $page){
            return $page->getOriginId();
        }, $this->pages);
    }

    /**
     * @param array $commands
     * @return string
     */
    private function parseCommands(array $commands)
    {
        $command = implode(" && ", $commands);

        return "($command)";
    }
}
