<?php

namespace KupShop\CatalogBundle\Repository;

use KupShop\CatalogBundle\Entity\Producer;
use KupShop\I18nBundle\Translations\ProducersTranslation;
use KupShop\KupShopBundle\Util\Entity\EntityUtil;
use Query\Filter;
use Query\Operator;
use Query\Product;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Contracts\Service\Attribute\Required;

class ProducersRepository
{
    private $sorting;
    private array $producers = [];
    private array $specs = [];
    private int $imageSize = 0;
    protected EntityUtil $entityUtil;

    public function getProducers($fetchImages = false): array
    {
        if ($this->producers) {
            return $this->producers;
        }

        /** @var QueryBuilder $qb */
        $qb = sqlQueryBuilder()->select('pr.*, 
        GROUP_CONCAT(DISTINCT b.content ORDER BY b.position ASC SEPARATOR "") AS description')
            ->from('producers', 'pr')
            ->leftJoin('pr', 'blocks', 'b', 'b.id_root = pr.id_block')
            ->where('pr.active="Y"')
            ->andWhere(Translation::coalesceTranslatedFields(ProducersTranslation::class,
                ['name' => 'name', 'web' => 'web', 'data' => 'data_translated']))
            ->groupBy('pr.id')
            ->orderBy('pr.position, pr.name');

        $products_qb = sqlQueryBuilder()->select('p.id')->fromProducts()
            ->where('p.producer = pr.id')
            ->andWhere(Product::isVisible());
        if (\Settings::getDefault()->prod_show_not_in_store == 'N') {
            $products_qb->andWhere(Filter::byInStore(\Filter::IN_STORE_SUPPLIER));
        }
        $qb->andWhere(Operator::exists($products_qb));

        // TODO: Hack, use parameter or request
        if ($this->sorting == 'alphabetically') {
            $qb->orderBy('pr.name, pr.position');
        }

        if (!empty($this->specs)) {
            $qb->andWhere(Operator::andX($this->specs));
        }

        $producers = [];
        foreach ($qb->execute() as $producer) {
            if (!empty($producer['photo'])) {
                $producer['image'] = getImage($producer['id'], $producer['photo'], '../producer/', 7, $producer['name'], strtotime($producer['date_updated']));
            } else {
                $producer['image'] = null;
            }

            $producer['data'] = array_replace_recursive(json_decode($producer['data'], true) ?: [], json_decode($producer['data_translated'], true) ?: []);

            $producers[$producer['id']] = $producer;
        }

        if ($fetchImages) {
            $photos = sqlQueryBuilder()->select('ppr.id_producer, p.id, p.descr, p.source, p.image_2')
                ->from('photos', 'p')
                ->join('p', 'photos_producers_relation', 'ppr', 'ppr.id_photo = p.id')
                ->andWhere(Operator::inIntArray(array_keys($producers), 'ppr.id_producer'))
                ->orderBy('ppr.position')
                ->execute();

            foreach ($photos as $photo) {
                $producers[$photo['id_producer']]['photos'][] = getImage($photo['id'], $photo['image_2'], $photo['source'], $this->imageSize, $photo['descr']);
            }
        }

        return $this->producers = $producers;
    }

    public function getProducerEntities($ids = []): array
    {
        $this->addSpec(function (QueryBuilder $qb) use ($ids) {
            $qb->andWhere(Operator::inIntArray($ids, 'pr.id'));
        });

        $producerEntities = [];
        foreach ($this->getProducers(true) as $id => $producer) {
            $producerEntities[$id] = $this->entityUtil->createEntity($producer, Producer::class, new CamelCaseToSnakeCaseNameConverter());
        }

        return $producerEntities;
    }

    public function getProducerEntity(int $id): ?Producer
    {
        return $this->getProducerEntities([$id])[$id] ?? null;
    }

    public function setSorting(mixed $sorting): void
    {
        $this->sorting = $sorting;
    }

    public function addSpec($spec): void
    {
        $this->specs[] = $spec;
    }

    public function setSecs($spec): void
    {
        $this->specs = $spec;
    }

    public function setImageSize(int $imageSize): void
    {
        $this->imageSize = $imageSize;
    }

    #[Required]
    public function setEntityUtil(EntityUtil $entityUtil): void
    {
        $this->entityUtil = $entityUtil;
    }
}
