<?php

declare(strict_types=1);

namespace KupShop\ComponentsBundle\Twig\DataProvider;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Driver\Exception;
use KupShop\CatalogBundle\Entity\Producer;
use KupShop\CatalogBundle\Entity\Section;
use KupShop\CatalogBundle\Entity\Wrapper\CategoryWrapper;
use KupShop\CatalogBundle\Repository\ProducersRepository;
use KupShop\CatalogBundle\Repository\SectionsRepository;
use KupShop\ComponentsBundle\Dto\SectionsMultiFetch;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ContentBundle\Util\SliderUtil;
use Query\Operator;
use Symfony\Component\Serializer\Exception\ExceptionInterface;

class SectionDataProvider
{
    private SectionsMultiFetch $multiFetch;

    /** @var CategoryWrapper[] */
    protected array $sections = [];

    /** @var Producer[] */
    protected array $producers = [];

    public function __construct(
        protected SectionsRepository $sectionsRepository,
        protected CategoryWrapper $sectionWrapper,
        protected ProducersRepository $producerRepository,
        protected SliderUtil $sliderUtil,
    ) {
        $this->multiFetch = new SectionsMultiFetch($this->sections, $sliderUtil);
    }

    public function addSection(Section|int $section): void
    {
        if (is_int($section)) {
            $sectionId = $section;
            $section = $this->sectionsRepository->findById((int) $sectionId);
        } else {
            $sectionId = $section->getId();
        }

        if ($section) {
            $this->sections[$sectionId] = (clone $this->sectionWrapper)->setObject($section);
        }
    }

    public function getSection(int $id_section): ?CategoryWrapper
    {
        if (!isset($this->sections[$id_section])) {
            $this->addSection($id_section);
        }

        return $this->sections[$id_section] ?? null;
    }

    public function addProducer(Producer $producer): void
    {
        if ($producer->getId()) {
            $this->producers[$producer->getId()] = $producer;
        }
    }

    public function getProducer(int $id_producer): ?Producer
    {
        if (!isset($this->producers[$id_producer]) && ($producer = $this->producerRepository->getProducerEntity($id_producer))) {
            $this->addProducer($producer);
        }

        return $this->producers[$id_producer] ?? null;
    }

    public function getName(int $id_section): string
    {
        return $this->getSection($id_section)['name'] ?? '';
    }

    public function getNameShort(int $id_section): string
    {
        return $this->getSection($id_section)['nameShort'] ?? '';
    }

    public function getNameShortOrName(int $id_section): string
    {
        return $this->getNameShort($id_section) ?: $this->getName($id_section);
    }

    public function getUrl(int $id_section): string
    {
        return $this->getSection($id_section)['fullUrl'] ?? '';
    }

    public function getThumbnail(int $id_section): ?Thumbnail
    {
        $section = $this->getSection($id_section)->getObject();
        if ($section->getPhotoFilename()) {
            return new Thumbnail((string) $section->getId(), $section->getName(), (string) $section->getDateUpdated()->format('Y-m-d H:i:s'));
        }

        return null;
    }

    public function getChildren(int $id_section): ?ArrayCollection
    {
        return $this->getSection($id_section)['children'] ?? null;
    }

    /**
     * @return Section[]
     *
     * @throws Exception
     * @throws ExceptionInterface
     * @throws \Doctrine\DBAL\Exception
     */
    public function loadSectionsBySpecs($specs = null): array
    {
        $menuSectionsQuery = sqlQueryBuilder()
            ->select('sr.id_section')
            ->from('sections_relation', 'sr')
            ->leftJoin('sr', 'sections', 's', 'sr.id_section = s.id')
            ->andWhere('sr.id_topsection IS NULL')
            ->andWhere('sr.id_section > 0')
            ->andWhere("s.figure = 'Y'")
            ->addOrderBy('sr.position');

        if ($specs) {
            $menuSectionsQuery->andWhere(Operator::andX($specs));
        }

        return $this->sectionsRepository->findManyById($menuSectionsQuery->execute()->fetchFirstColumn());
    }

    /**
     * @return Section[]
     */
    public function getSections(): array
    {
        return $this->sections;
    }

    public function multiFetch(): SectionsMultiFetch
    {
        return $this->multiFetch;
    }
}
