<?php
namespace Backend\BaseBundle\Service;


use Backend\BaseBundle\Exception\ErrorResponseException;
use Backend\BaseBundle\Model\Site;
use Backend\BaseBundle\Model\SiteQuery;
use Backend\BaseBundle\SiteConfig\SiteConfigBuilder;
use JMS\DiExtraBundle\Annotation as DI;
use JMS\DiExtraBundle\Annotation\Inject;
use JMS\DiExtraBundle\Annotation\InjectParams;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Process\ProcessBuilder;

/**
 * @DI\Service("server_side_render")
 */
class ServerSideRender
{
    /** @var  Site */
    protected $site;

    /** @var  SiteConfigBuilder */
    protected $siteConfigBuilder;

    protected $cacheDir;
    protected $kernelRootDir;


    /**
     * @InjectParams({
     *    "siteConfigBuilder" = @Inject("backend_base.site_config_builder"),
     * })
     */
    public function injectSiteConfigBuilder(SiteConfigBuilder $siteConfigBuilder)
    {
        $this->siteConfigBuilder = $siteConfigBuilder;
    }

    /**
     * @InjectParams({
     *     "slug" = @Inject("%slug%")
     * })
     */
    public function injectSlug($slug)
    {
        $this->site = SiteQuery::create()->findOneBySlug($slug);
    }

    /**
     * @InjectParams({
     *     "cacheDir" = @Inject("%kernel.cache_dir%"),
     *     "kernelRootDir" = @Inject("%kernel.root_dir%")
     * })
     */
    public function injectDir($cacheDir, $kernelRootDir)
    {
        $this->cacheDir = $cacheDir;
        $this->kernelRootDir = $kernelRootDir;
    }

    protected function makeTempName()
    {
        return tempnam($this->cacheDir, md5(self::class));
    }

    /**
     * @param $url
     * @return Response
     */
    public function render($url)
    {
        if($url === null){
            throw new BadRequestHttpException();
        }

        $parsed = parse_url($url);
        $domains = $this->findAcceptDomain();

        if(!$parsed || !isset($parsed['host']) || !isset($parsed['scheme']) || !preg_match('/^https?$/i', $parsed['scheme'])) {
            throw new NotAcceptableHttpException();
        }

        $hostPort = $parsed['host'];
        if(isset($parsed['port'])){
            $hostPort.=":{$parsed['port']}";
        }

        if(!$domains || !in_array($hostPort, $domains)){
            throw new AccessDeniedHttpException();
        }

        if(!($scriptPath = $this->getFetchScriptPath())){
            throw new NotFoundHttpException();
        }

        $tmpOutput = $this->makeTempName();

        $builder = new ProcessBuilder();
        $process = $builder->setPrefix('env')
            ->setArguments(array(
                'phantomjs',
                '--proxy-type=none',
                '--ignore-ssl-errors=true',
                '--load-images=false',
                '--local-to-remote-url-access=true',
                $scriptPath,
                $tmpOutput,
                $url,
            ))
            ->getProcess()
        ;
        $process->run();
        $result = json_decode(file_get_contents($tmpOutput), true);
        @unlink($tmpOutput);
        return $result;
    }

    protected function getFetchScriptPath()
    {
        return realpath($this->kernelRootDir.'/../seo/fetch.js');
    }

    protected function findAcceptDomain()
    {
        $config = $this->siteConfigBuilder->build($this->site->getId())->get('system');

        if(!isset($config['domains'])){
            return null;
        }

        return explode(',', trim($config['domains']));
    }
}