<?php

namespace AutoAdmin\Bundle\Seo\Extractor;

use AutoAdmin\Bundle\Content\Configuration\ConfigManager;
use AutoAdmin\Bundle\Content\Context\ContentContext;
use AutoAdmin\Bundle\Content\Model\TranslatableInterface;
use AutoAdmin\Bundle\Content\Routing\ContentRouter;
use AutoAdmin\Bundle\Content\Site\SiteContextHelper;
use AutoAdmin\Bundle\Content\Translation\LocaleSwitchHelper;
use AutoAdmin\Bundle\Seo\Entity\SeoMetadata;
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 Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Service\Attribute\Required;

class SeoContentExtractor extends AbstractExtractor
{
    protected ContentContext $contentContext;
    protected LocaleSwitchHelper $localeSwitchHelper;

    public function __construct(
        protected ConfigManager $config,
        protected ContentRouter $contentRouter,
        protected SiteContextHelper $contextHelper,
    ) {
    }

    #[Required]
    public function inject(
        ContentContext $contentContext,
        LocaleSwitchHelper $localeSwitchHelper,
    ): void {
        $this->contentContext = $contentContext;
        $this->localeSwitchHelper = $localeSwitchHelper;
    }

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

    public function extract(Request $request, object $subject, SeoPage $seoPage): SeoPage
    {
        [$translatable, $translation] = $this->getTranslatableTranslationObjects($subject);

        if (
            $translation instanceof SeoContentTranslationInterface
            && ($seoMetadata = $translation->getSeoMetadata()) !== null
        ) {
            $this->handleTitle($seoMetadata, $seoPage);

            $this->handleDescription($seoMetadata, $seoPage);

            $this->handleMetas($seoMetadata, $seoPage);

            $this->handleCanonical($seoMetadata, $seoPage, $request);

            $this->handleRobotsTag($seoMetadata, $seoPage);
        }

        if ($translatable instanceof TranslatableInterface) {
            $this->handleAlternates($translatable, $seoPage, $request);
        }

        return $seoPage;
    }

    protected function handleTitle(SeoMetadata $seoMetadata, SeoPage $seoPage): void
    {
        if (!$seoMetadata->getTitle()) {
            return;
        }

        $seoPage->setTitle($this->sanitize($seoMetadata->getTitle()));
    }

    protected function handleDescription(SeoMetadata $seoMetadata, SeoPage $seoPage): void
    {
        if (!$seoMetadata->getDescription()) {
            return;
        }

        $seoPage->addMeta(
            new Meta(
                'description',
                $this->sanitize($seoMetadata->getDescription())
            )
        );
    }

    protected function handleMetas(SeoMetadata $seoMetadata, SeoPage $seoPage): void
    {
        if (empty($metas = $seoMetadata->getMetas())) {
            return;
        }

        foreach ($metas as $meta => $value) {
            $seoPage->addMeta(new Meta($meta, $value));
        }
    }

    protected function handleCanonical(SeoMetadata $seoMetadata, SeoPage $seoPage, Request $request): void
    {
        if (!empty($seoMetadata->getCanonicalOverride())) {
            $seoPage->setCanonical($seoMetadata->getCanonicalOverride());
        } else {
            $seoPage->setCanonical(strtok($request->getUri(), '?'));
        }
    }

    protected function handleRobotsTag(SeoMetadata $seoMetadata, SeoPage $seoPage): void
    {
        $xRobotsTag = [];
        if ($seoMetadata->isNoIndex()) {
            $xRobotsTag[] = 'noindex';
        }

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

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

    protected function handleAlternates(TranslatableInterface $translatable, SeoPage $seoPage): void
    {
        $alternates = [];

        $localeSwitches = [
            $this->localeSwitchHelper->buildCurrentSwitch($translatable),
            ...$this->localeSwitchHelper->buildAlternateSwitches($translatable),
        ];
        foreach ($localeSwitches as $ls) {
            if ($ls->getUrl()) {
                $alternates[] = new Alternate($ls->getLocale(), $ls->getUrl());
            }
        }

        $seoPage->setAlternates($alternates);
    }
}
