<?php

namespace KupShop\CDNBundle\Controller;

use KupShop\KupShopBundle\Util\System\UrlFinder;
use Psr\Log\LoggerInterface;
use Query\Operator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
use Symfony\Component\Routing\Annotation\Route;

class CDNController extends AbstractController
{
    /** @var LoggerInterface */
    protected $logger;

    /**
     * @required
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }

    /**
     * @Route("/_cdn/", methods={"POST"})
     *
     * @return Response
     */
    public function WebhookAction(Request $request)
    {
        if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
            $data = json_decode($request->getContent(), true);
            $this->logger->notice('CDN Webhook Request', [
                'url' => $request->getUri(),
                'data' => $data,
            ]);

            /* Status finished */
            if ($data['Status'] === 3) {
                $photo = sqlQueryBuilder()
                    ->select('p.id id, p.filename, p.descr, v.id_cdn id_video')
                    ->from('photos', 'p')
                    ->innerJoin('p', 'videos', 'v', 'p.id = v.id_photo')
                    ->where(Operator::equals(['id_cdn' => $data['VideoGuid']]))
                    ->execute()
                    ->fetch();
                if ($photo) {
                    $img = new \Photos();
                    $img->newImage($photo['id']);
                    if (!$img->refreshVideoThumbnail($photo)) {
                        $this->logger->notice('CDN Webhook Failed', [
                            'url' => $request->getUri(),
                            'data' => $data,
                        ]);
                    }
                }
            }

            return new Response('OK', 200);
        }

        return new Response('', 400);
    }

    /**
     * @Route("/_cdn/typekit/{id}")
     *
     * @return Response
     */
    public function typekitAction(string $id, UrlFinder $urlFinder)
    {
        $url = "https://use.typekit.net/{$id}.css";

        $response = $this->downloadToResponse($url);
        $css = $response->getContent();

        // Remove tracking url
        $css = preg_replace('@^.*https://p\.typekit\.net.*$@m', '', $css);

        if ($urlFinder->hasCDN()) {
            // Replace font urls
            $css = preg_replace('@https://use\.typekit\.net@m', $urlFinder->staticUrlAbsolute('/_cdn/font'), $css);
        }

        $response->setContent($css);

        return $response;
    }

    /**
     * @Route("/_cdn/font/{path}", requirements={"path":".*"})
     *
     * @return Response
     */
    public function typekitFontAction(Request $request, string $path)
    {
        $url = "https://use.typekit.net/{$path}?{$request->getQueryString()}";

        return $this->downloadToResponse($url);
    }

    protected function downloadToResponse(string $url): Response
    {
        $ch = curl_init();
        $headers = [];
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        // this function is called by curl for each header received
        curl_setopt($ch, CURLOPT_HEADERFUNCTION,
            function ($curl, $header) use (&$headers) {
                $len = strlen($header);
                $header = explode(':', $header, 2);
                if (count($header) < 2) { // ignore invalid headers
                    return $len;
                }

                $headers[strtolower(trim($header[0]))][] = trim($header[1]);

                return $len;
            }
        );

        $data = curl_exec($ch);

        unset($headers['content-length']);

        $response = new Response($data);
        $response->headers->replace($headers);

        // Force cacheable
        $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
        $response->setPublic();
        $response->setMaxAge(3600);

        return $response;
    }
}
