<?php


namespace BrandCrockAquaTheme\Subscriber;

use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingsLoadedEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingIdsCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingStreamCriteriaEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageCriteriaEvent;
use Shopware\Storefront\Page\Wishlist\WishlistPageLoadedEvent;
use Shopware\Storefront\Page\Wishlist\WishListPageProductCriteriaEvent;

class PageLoadedEventSubscriber implements EventSubscriberInterface
{
    private $productRepository;
    private $mediaRepository;

    public function __construct(EntityRepository $repository, EntityRepository $mediaRepository)
    {
        $this->productRepository = $repository;
        $this->mediaRepository = $mediaRepository;
    }

    public static function getSubscribedEvents()
    {
        return [
            ProductListingResultEvent::class => 'onProductListingResultEvent',
            ProductSearchResultEvent::class => 'onProductSearchResultEvent',
            ProductCrossSellingsLoadedEvent::class => 'onCrossSellingLoaded',
            ProductPageLoadedEvent::class => 'onProductPageLoaded',
            ProductListingCriteriaEvent::class => 'onProductListingCriteriaEvent',
            ProductCrossSellingIdsCriteriaEvent::class => 'onProductCrossSellingIdsCriteriaEvent',
            ProductSearchCriteriaEvent::class => 'onProductSearchCriteriaEvent',
            MinimalQuickViewPageCriteriaEvent::class => 'onMinimalQuickViewPageCriteriaEvent',
            WishListPageProductCriteriaEvent::class => 'onWishListPageProductCriteriaEvent',
            ProductCrossSellingStreamCriteriaEvent::class => 'onProductCrossSellingStreamCriteriaEvent',
            WishlistPageLoadedEvent::class => 'onWishlistPageLoadedEvent',
        ];
    }

    public function onCrossSellingLoaded(ProductCrossSellingsLoadedEvent $event)
    {
        foreach ($event->getCrossSellings() as $element) {
            $productElements = $element->getProducts()?->getElements();

            if ($productElements) {
                $this->addVariantOptionsInProductResults($productElements, $event);
            }
        }
    }

    public function onProductPageLoaded(ProductPageLoadedEvent $event): void
    {
        $context = $event->getSalesChannelContext()->getContext();
        $product = $event->getPage()->getProduct();

        $productTranslated = $product->getTranslated();

        if (!isset($productTranslated['customFields'])) return;

        $customData = $productTranslated['customFields'];

        if (empty($customData)) return;

        $pdfKeys = [
            'custom_bc_pdf_tab1' => 'file1',
            'custom_bc_pdf_tab2' => 'file2',
            'custom_bc_pdf_tab3' => 'file3',
        ];

        $mediaIds = [];

        foreach ($pdfKeys as $field => $key) {
            if (!empty($customData[$field])) {
                $mediaIds[$key] = $customData[$field];
            }
        }

        $attachments = [];

        if (!empty($mediaIds)) {
            $criteria = new Criteria(array_values($mediaIds));
            $mediaCollection = $this->mediaRepository->search($criteria, $context);

            foreach ($mediaIds as $key => $id) {
                $media = $mediaCollection->get($id);

                if (!$media) continue;

                $attachments[$key] = [
                    'extension' => $media->getFileExtension(),
                    'name' => $media->getFileName(),
                    'url' => $media->getUrl(),
                ];
            }
        }

        if (!empty($attachments)) {
            $event->getPage()->addExtension('attachmentsData', new ArrayEntity($attachments));
        }
    }

    public function onMinimalQuickViewPageCriteriaEvent(MinimalQuickViewPageCriteriaEvent $event): void
    {
        $criteria = $event?->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function onWishListPageProductCriteriaEvent(WishListPageProductCriteriaEvent $event)
    {
        $criteria = $event?->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function onProductListingResultEvent(ProductListingResultEvent $event): void
    {
        $elements = $event->getResult()?->getElements();
        $this->addVariantOptionsInProductResults($elements, $event);
    }

    public function onProductSearchResultEvent(ProductSearchResultEvent $event): void
    {
        $elements = $event->getResult()?->getElements();
        $this->addVariantOptionsInProductResults($elements, $event);
    }

    public function onProductListingCriteriaEvent(ProductListingCriteriaEvent $event)
    {
        $criteria = $event?->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function onProductCrossSellingIdsCriteriaEvent(ProductCrossSellingIdsCriteriaEvent $event)
    {
        $criteria = $event->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function onProductCrossSellingStreamCriteriaEvent(ProductCrossSellingStreamCriteriaEvent $event): void
    {
        $criteria = $event?->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function onProductSearchCriteriaEvent(ProductSearchCriteriaEvent $event): void
    {
        $criteria = $event?->getCriteria();

        if (!empty($criteria)) {
            $this->addDefaultProductCriteriaAssociations($criteria);
        }
    }

    public function addDefaultProductCriteriaAssociations(Criteria|null $criteria): void
    {
        if (empty($criteria)) return;

        $criteria->addAssociation('manufacturer');
        $criteria->addAssociation('media.media');
    }

    public function addVariantOptionsInProductResults(Array|null $elements, $event): void
    {
        if (empty($elements)) return;

        $parentIds = [];

        foreach ($elements as $product) {
            if ($product->getParentId() === null && $product->getChildCount() > 0) {
                $parentIds[] = $product->getId();
            }
        }

        $variantsCriteria = new Criteria();
        $variantsCriteria->addFilter(new EqualsAnyFilter('parentId', $parentIds));
        $variantsCriteria->addAssociations([
            'options',
            'options.group',
            'options.media',
            'cover.media'
        ]);

        $variants = $this->productRepository
            ->search($variantsCriteria, $event->getContext())
            ->getElements();

        $variantsByParent = [];

        foreach ($variants as $variant) {
            $variantsByParent[$variant->getParentId()][] = $variant;
        }

        foreach ($elements as $product) {
            if ($product->getParentId() !== null || $product->getChildCount() === 0) continue;

            $productId = $product->getId();

            if (!isset($variantsByParent[$productId])) continue;

            $productCoverMedia = $product->getCover()?->getMedia();
            $productCoverId = $productCoverMedia?->getId();
            $productCoverUrl = $productCoverMedia?->getUrl();

            $variantsOptions = [];

            foreach ($variantsByParent[$productId] as $variant) {
                $variantCoverMedia = $variant->getCover()?->getMedia();
                $variantCoverId = $variantCoverMedia?->getId();

                $variantCoverUrl = (
                    empty($variantCoverId) || $variantCoverId === $productCoverId
                ) ? $productCoverUrl : $variantCoverMedia?->getUrl();

                foreach ($variant->getOptions() as $option) {
                    $group = $option->getGroup();
                    $groupName = $group->getName();
                    $displayType = $group->getDisplayType();
                    $optionName = $option->getName();

                    if (isset($variantsOptions[$groupName][$optionName])) continue;

                    $variantsOptions[$groupName][$optionName] = [
                        'displayType' => $displayType,
                        'name' => $optionName,
                        'colorCode' => $option->getColorHexCode(),
                        'variantId' => $variant->getId(),
                        'image' => $variantCoverUrl,
                        'optionImage' => $option?->getMedia()?->getUrl()
                    ];
                }
            }

            foreach ($variantsOptions as &$group) {
                $group = array_values($group);
            }

            $product->addExtension(
                'bcVariantOptions',
                new ArrayEntity(['groups' => $variantsOptions])
            );
        }
    }

    public function onWishlistPageLoadedEvent(WishlistPageLoadedEvent $event)
    {
        $elements = $event?->getPage()?->getWishlist()?->getProductListing()->getElements();
        $this->addVariantOptionsInProductResults($elements, $event);
    }
}
