<?php

namespace AutoAdmin\Bundle\Seo\Sitemap;

use AutoAdmin\Bundle\Content\Configuration\ConfigManager;
use AutoAdmin\Bundle\Content\Model\CreatedAtInterface;
use AutoAdmin\Bundle\Content\Model\TranslatableInterface;
use AutoAdmin\Bundle\Content\Model\UpdatedAtInterface;
use AutoAdmin\Bundle\Content\Routing\ContentRouter;
use AutoAdmin\Bundle\Content\Site\SiteContextHelper;
use AutoAdmin\Bundle\Seo\Model\SeoContentTranslationInterface;
use AutoAdmin\Bundle\Seo\Sitemap\Model\SitemapUrl;
use DateTime;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Contracts\Service\Attribute\Required;

abstract class AbstractSitemapBuilder implements SitemapBuilderInterface
{
    protected readonly ConfigManager $configManager;
    protected readonly ManagerRegistry $doctrine;
    protected readonly SiteContextHelper $siteContextHelper;
    protected readonly ContentRouter $contentRouter;

    #[Required]
    public function init(
        ConfigManager $configManager,
        ManagerRegistry $doctrine,
        SiteContextHelper $siteContextHelper,
        ContentRouter $contentRouter
    ): void
    {
        $this->configManager = $configManager;
        $this->doctrine = $doctrine;
        $this->siteContextHelper = $siteContextHelper;
        $this->contentRouter = $contentRouter;
    }

    public function getUrls(?string $section = null): array
    {
        $safeUrlGen = ($cfg = $this->configManager->get('sitemap')) && $cfg['safe_url_generation'] === true;

        $urls = [];

        // after builders, generate content sitemap from config
        $sitemapConfig = $this->configManager->getSitemap();
        foreach ($sitemapConfig['config'] as $sectionSlug => $sectionConfig) {
            if ($sectionConfig['disable'] === true || $sectionSlug !== $section) {
                continue;
            }

            foreach ($sectionConfig['contents'] as $contentSlug) {
                $contentCfg = $this->configManager->getContentConfigForSlug($contentSlug);
                $contentClass = $contentCfg['class'];

                $contents = $this->resolveContents($contentClass);
                $urlAction = !empty($contentCfg['action_chain']) ? 'chain' : 'view';
                $changeFreq = $contentCfg['sitemap']['changefreq'];

                foreach ($contents as $content) {
                    $tr = $content instanceof TranslatableInterface ? $content->getCurrentTranslation() : null;
                    $date = new DateTime();
                    if ($content instanceof UpdatedAtInterface) {
                        $date = $content->getUpdatedAt();
                    } elseif ($content instanceof CreatedAtInterface) {
                        $date = $content->getCreatedAt();
                    }

                    if ($content instanceof SeoContentTranslationInterface) {
                        $seoHolder = $content;
                    } elseif ($tr instanceof SeoContentTranslationInterface) {
                        $seoHolder = $tr;
                    } else {
                        $seoHolder = null;
                    }

                    $hideFromSitemap = false;
                    $canonicalOverride = '';
                    $differentCanonicalDomain = false;
                    if ($seoHolder) {
                        $hideFromSitemap = ($seoHolder->getSeoMetadata()?->isHideFromSitemap() === true);

                        $canonicalOverride = $seoHolder->getSeoMetadata()?->getCanonicalOverride();
                        if (!empty($canonicalOverride)) {
                            $relativeOverride = str_starts_with((string)$canonicalOverride, '/');
                            // if override is not relative,
                            // then domain should be provided by override and checked against site context
                            if (!$relativeOverride) {
                                $parsedCanonical = parse_url($canonicalOverride);

                                // we need a host if canonical is not relative, otherwise syntax is not good
                                if (empty($parsedCanonical['host'])) {
                                    continue;
                                }

                                if (
                                    $parsedCanonical['host'] === $this->siteContextHelper->getDomain()->getDomain()
                                    && $parsedCanonical['scheme']
                                ) {
                                    $schemeHost = $parsedCanonical['scheme'] . '://' . $parsedCanonical['host'];
                                    $canonicalOverride = str_replace($schemeHost, '', $canonicalOverride);
                                } else {
                                    $differentCanonicalDomain = true;
                                }
                            }
                        }
                    }

                    if ($hideFromSitemap || $differentCanonicalDomain) {
                        continue;
                    }

                    if (!empty($canonicalOverride)) {
                        $url = $canonicalOverride;
                    } else {
                        if ($safeUrlGen) {
                            $url = $this->contentRouter->generateSafe($content, $urlAction);
                        } else {
                            $url = $this->contentRouter->generate($content, $urlAction);
                        }
                    }

                    $sitemapUrl = new SitemapUrl($url, $date, $changeFreq);
                    $urls[] = $sitemapUrl;
                }
            }
        }

        foreach ($sitemapConfig['routes'] as $sectionSlug => $routeConfigs) {
            if ($sectionSlug !== $section) {
                continue;
            }

            foreach ($routeConfigs as $routeConfig) {
                $route = $routeConfig['route'];
                [$contentSlug, $action] = explode('_', $route, 2);
                $param = $routeConfig['param'];
                if (!empty($param['slugAdmin'])) {
                    $url = $this->contentRouter->generate($contentSlug, $action, $param ?? []);
                } else {
                    $url = $this->contentRouter->getRouter()->generate($route, $param ?? []);
                }

                $sitemapUrl = new SitemapUrl($url, new DateTime(), SitemapUrl::DEFAULT_CHANGE_FREQ);
                $urls[] = $sitemapUrl;
            }
        }

        return $urls;
    }
}
