<?php


namespace AutoAdmin\Bundle\Content\Site;


use AutoAdmin\Bundle\Content\Context\SiteContext;
use AutoAdmin\Bundle\Content\Entity\Domain;
use AutoAdmin\Bundle\Content\Entity\Locale;
use AutoAdmin\Bundle\Content\Entity\Site;
use AutoAdmin\Bundle\Content\Model\LocaleInterface;
use AutoAdmin\Bundle\Content\Model\SiteConfig;
use AutoAdmin\Bundle\Content\Translation\EntityTranslator;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use RuntimeException;

class SiteContextHelper
{
    private ManagerRegistry $doctrine;
    private SiteContext $siteContext;
    private EntityTranslator $entityTranslator;

    public function __construct(ManagerRegistry $doctrine, SiteContext $siteContext, EntityTranslator $entityTranslator)
    {
        $this->doctrine = $doctrine;
        $this->siteContext = $siteContext;
        $this->entityTranslator = $entityTranslator;
    }

    public function isSite(Site $site): bool
    {
        return $this->siteContext->getSite()->getId() === $site->getId();
    }

    public function loadSiteConfig(SiteConfig $siteConfig): void
    {
        $this->loadSiteAndLocale($siteConfig->getSite(), $siteConfig->getLocale());
    }

    public function loadSiteAndLocale(Site $site, Locale $locale): void
    {
        $this->applySiteAndLocale($site, $locale);

        $managers = $this->doctrine->getManagers();
        foreach ($managers as $manager) {
            $this->prepareEntityManager($manager);
        }
    }

    protected function applySiteAndLocale(Site $site, Locale $locale): void
    {
        $this->siteContext->setSite($site);
        $this->siteContext->setLocale($locale);
        $this->entityTranslator->setLocale($locale);
    }

    public function prepareEntityManager(ObjectManager $em): void
    {
        $site = $this->siteContext->getSite();
        $locale = $this->siteContext->getLocale();
        if (null === $site || null === $locale) {
            throw new RuntimeException('Site or locale is not defined, cannot initialize ObjectManager.');
        }

        /** @var Site $site */
        $site = $em->getRepository(Site::class)->find($site->getId());
        /** @var Locale $locale */
        $locale = $em->getRepository(Locale::class)->find($locale->getId());
        /** @var EntityManagerInterface $em */
        $this->applySiteAndLocale($site, $locale);
    }

    public function loadSiteAndDefaultLocale(Site $site): void
    {
        $locale = $this->doctrine->getRepository(Locale::class)->findOneBy(['code' => 'fr']);

        $this->loadSiteAndLocale($site, $locale);
    }

    /**
     * @return SiteConfig[]
     */
    public function getAllSiteConfigs(): array
    {
        /** @var Site[] $sites */
        $sites = $this->doctrine->getRepository(Site::class)->findAll();
        $siteConfigs = [];
        foreach ($sites as $site) {
            $siteConfigs = $this->getSiteLocalizedDomains($site, $siteConfigs);
        }

        return $siteConfigs;
    }

    /**
     * @return SiteConfig[]
     */
    public function getSiteLocalizedDomains(Site $site = null, array $tab = null): array
    {
        if ($site === null) {
            $site = $this->siteContext->getSite();
        }

        $tab = $tab ?? [];

        /** @var Domain $domain */
        foreach ($site->getDomains() as $domain) {
            /** @var Locale $locale */
            foreach ($domain->getLocales() as $locale) {
                $tab[] = new SiteConfig($site, $domain, $locale);
            }
        }

        return $tab;
    }

    public function getDomainByLocale(Site $site, LocaleInterface $locale = null): ?Domain
    {
        if ($locale === null) {
            $locale = $this->getCurrentContext()->getLocale();
        }

        $found = null;

        /** @var Domain $domain */
        foreach ($site->getDomains() as $domain) {
            /** @var LocaleInterface $locale */
            foreach ($domain->getLocales() as $locale) {
                if ($locale->getCode() == $locale->getCode()) {
                    $found = $domain;
                    break 2;
                }
            }
        }

        return $found;
    }

    public function getCurrentContext(): SiteContext
    {
        return $this->siteContext;
    }

    public function getSiteLocaleForCode(string $localeCode): ?LocaleInterface
    {
        foreach ($this->getSiteLocalizedDomains($this->siteContext->getSite()) as $siteConfig) {
            if ($siteConfig->getLocale()->getCode() === $localeCode) {
                return $siteConfig->getLocale();
            }
        }

        return null;
    }
}
