<?php


namespace AutoAdmin\Bundle\Seo\Extractor;


use AutoAdmin\Bundle\Content\Configuration\ConfigManager;
use AutoAdmin\Bundle\Content\Context\ContentContext;
use AutoAdmin\Bundle\Content\Entity\Page;
use AutoAdmin\Bundle\Content\Model\TranslatableInterface;
use AutoAdmin\Bundle\Content\Model\TranslationInterface;
use AutoAdmin\Bundle\Content\Routing\ContentRouter;
use AutoAdmin\Bundle\Content\Site\SiteContextHelper;
use AutoAdmin\Bundle\Seo\Model\Alternate;
use AutoAdmin\Bundle\Seo\Model\Header;
use AutoAdmin\Bundle\Seo\Model\Meta;
use AutoAdmin\Bundle\Seo\Model\SeoPage;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;

class SeoContentExtractor extends AbstractExtractor
{
    public function __construct(
        protected ConfigManager $config,
        protected ContentRouter $contentRouter,
        protected SiteContextHelper $contextHelper,
        protected EntityManagerInterface $em,
    ) {
    }

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

    public function extract(Request $request, $subject, $seo): SeoPage
    {
        $homepage = $this->getHomepage();

        list($translatable, $translation) = $this->getTranslatableTranslationObjects($subject);

        $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
        $alternates = [];
        if ($translatable instanceof TranslatableInterface) {
            $route = $request->get('_route');
            $action = $this->config->getRouteAction($route);

            // null action usually mean we are out of content routes, for example in contact controller
            // use the main content if page is provided and override route and action
            if (
                $action === null
                && ($refl = new \ReflectionClass($translatable))
                && $refl->isSubclassOf(Page::class)
            ) {
                $route = 'page';
                $action = 'view';
            }

            /** @var TranslationInterface $translation */
            foreach ($translatable->getTranslations() as $localeTrans) {
                $locale = $localeTrans->getLocale();
                // check if route is localized (route name ending with locale part: .fr, .en)
                // if that's the case, get right locale
                if (
                    preg_match("/(.+?)(\.([a-z]{2}))/", $route, $matches)
                    && !empty($localeCode = $matches[3])
                ) {
                    $locale = $this->contextHelper->getSiteLocaleForCode($localeCode);
                }

                $domain = $this->contextHelper->getDomainByLocale($translatable->getSite(), $locale);
                $url = $this->contentRouter->generate(
                    $translatable,
                    $action,
                    ['_locale' => $locale->getCode(),],
                    ['host' => $domain->getDomain(),]
                );

                $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;
    }
}