<?php


namespace AutoAdmin\Bundle\Seo\Extractor;


use AutoAdmin\Bundle\Content\Configuration\ConfigManager;
use AutoAdmin\Bundle\Content\Model\TranslatableInterface;
use AutoAdmin\Bundle\Content\Model\TranslationInterface;
use AutoAdmin\Bundle\Content\Routing\ContentRouter;
use AutoAdmin\Bundle\Seo\Model\Alternate;
use AutoAdmin\Bundle\Seo\Model\Header;
use AutoAdmin\Bundle\Seo\Model\Meta;
use AutoAdmin\Bundle\Seo\Model\SeoContentTranslationInterface;
use AutoAdmin\Bundle\Seo\Model\SeoPage;
use Exception;
use Symfony\Component\HttpFoundation\Request;

class SeoContentExtractor extends AbstractExtractor
{
    private ConfigManager $config;
    private ContentRouter $contentRouter;

    public function __construct(ConfigManager $configManager, ContentRouter $contentRouter)
    {
        $this->config = $configManager;
        $this->contentRouter = $contentRouter;
    }

    public function supports($subject, $route): bool
    {
        return $this->isClassicalTransContent($subject) || $this->isUntranslatedContent($subject);
    }

    protected function isClassicalTransContent(object $subject): bool
    {
        return $subject instanceof TranslatableInterface && $subject->getCurrentTranslation() !== null;
    }

    protected function isUntranslatedContent(object $subject): bool
    {
        return $subject instanceof SeoContentTranslationInterface;
    }

    public function extract(Request $request, $subject): SeoPage
    {
        if ($this->isClassicalTransContent($subject)) {
            // classical content
            $translatable = $subject;
            $translation = $subject->getCurrentTranslation();
        } elseif ($this->isUntranslatedContent($subject)) {
            // untranslated content, self act as translatable and translation
            $translatable = $translation = $subject;
        } else {
            throw new Exception('Main content should implement some kind of SEO');
        }

        $seo = new SeoPage();
        $seoMetadata = $translation->getSeoMetadata();

        if ($seoMetadata->getTitle() && ($title = $this->sanitize($seoMetadata->getTitle()))) {
            $seo->setTitle($title);
        }

        if ($seoMetadata->getDescription() && ($desc = $this->sanitize($seoMetadata->getDescription()))) {
            $seo->addMeta(new Meta('description', $desc));
        }

        if (!empty($metas = $seoMetadata->getMetas())) {
            foreach ($metas as $meta => $value) {
                $seo->addMeta(new Meta($meta, $value));
            }
        }

        // canonical
        if (!empty($seoMetadata->getCanonicalOverride())) {
            $seo->setCanonical($seoMetadata->getCanonicalOverride());
        } else {
            $seo->setCanonical(strtok($request->getUri(), '?'));
        }

        // alternates (really slow ~600ms, we need to fix this)
        $alternates = [];
        if ($translatable instanceof TranslatableInterface) {
            $route = $request->get('_route');
            $action = $this->config->getRouteAction($route);
            /** @var TranslationInterface $translation */
            foreach ($translatable->getTranslations() as $translation) {
                $locale = $translation->getLocale();
                $url = $this->contentRouter->generate($translatable, $action, ['locale' => $locale,]);
                $alternates[] = new Alternate($locale, $url);
            }
        }
        $seo->setAlternates($alternates);

        // noindex/nofollow
        $xRobotsTag = [];
        if ($seoMetadata->isNoIndex() === true) {
            $xRobotsTag[] = 'noindex';
        }

        if ($seoMetadata->isNoFollow() === true) {
            $xRobotsTag[] = 'nofollow';
        }

        if ($xRobotsTag) {
            $seo->addResponseHeader(new Header('X-Robots-Tag', implode(', ', $xRobotsTag)));
        }

        return $seo;
    }
}