<?php
namespace Newland\NeosNodeTypes\Video;

use Newland\NeosNodeTypes\Exception\UnknownVideoException;

class YoutubeVideo extends AbstractVideo
{
    public const PREVIEW_URL = '%s//i.ytimg.com/vi/%s/%s';

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

    public function __construct(string $url)
    {
        $this->videoId = $this->extractVideoId($url);
    }

    public function getEmbedUrl(): string
    {
        return sprintf('//www.youtube-nocookie.com/embed/%s?rel=0&autoplay=1', $this->videoId);
    }

    public function getPreviewUrl(): string
    {
        if ($this->hasMaxResolutionPreviewImage()) {
            return $this->getPreviewImageUrl('maxresdefault.jpg');
        }

        if ($this->hasMediumQualityPreviewImage()) {
            return $this->getPreviewImageUrl('mqdefault.jpg');
        }

        return $this->getPreviewImageUrl('sddefault.jpg');
    }

    protected function hasMaxResolutionPreviewImage(): bool
    {
        return $this->checkPreviewImageExists('maxresdefault.jpg');
    }

    protected function hasMediumQualityPreviewImage(): bool
    {
        return $this->checkPreviewImageExists('mqdefault.jpg');
    }

    private function extractVideoId(string $url): string
    {
        $parsed = parse_url($url);

        if ($parsed === false) {
            throw new UnknownVideoException(sprintf('The url %s cannot be parsed.', $url));
        }

        // Regular youtube urls: https://youtube.com/watch?v={ID_GOES_HERE}
        if (array_key_exists('query', $parsed)
            && preg_match('/v=(.+)/', $parsed['query'], $queryMatches)
        ) {
            return $queryMatches[1];
        }

        // New youtu.be urls: https://youtu.be/{ID_GOES_HERE}
        if (array_key_exists('host', $parsed)
            && $parsed['host'] === 'youtu.be'
        ) {
            return str_replace('/', '', $parsed['path']);
        }

        // Embed urls: https://www.youtube.com/embed/{ID_GOES_HERE}
        if (array_key_exists('path', $parsed)
            && preg_match('/\/embed\/(\w+)/', $parsed['path'], $pathMatches)
        ) {
            return $pathMatches[1];
        }

        throw new UnknownVideoException(sprintf('The url %s cannot be parsed as Youtube URL', $url));
    }

    private function checkPreviewImageExists(string $filename): bool
    {
        $url = sprintf(self::PREVIEW_URL, 'https:', $this->videoId, $filename);
        $headers = get_headers($url);

        return substr($headers[0], 9, 3) !== '404';
    }

    private function getPreviewImageUrl(string $filename): string
    {
        return sprintf(self::PREVIEW_URL, '', $this->videoId, $filename);
    }
}
