<?php
/**
 * For the full copyright and license information, please view the
 * docs/licenses/LICENSE.txt file that was distributed with this source code.
 */
declare(strict_types=1);

namespace PrestaShopBundle\Controller\Admin\Sell\Catalog\Product;

use Exception;
use PrestaShop\PrestaShop\Adapter\Product\Image\ProductImagePathFactory;
use PrestaShop\PrestaShop\Core\Domain\AttributeGroup\Attribute\QueryResult\Attribute;
use PrestaShop\PrestaShop\Core\Domain\AttributeGroup\Query\GetAttributeGroupList;
use PrestaShop\PrestaShop\Core\Domain\AttributeGroup\QueryResult\AttributeGroup;
use PrestaShop\PrestaShop\Core\Domain\Product\AttributeGroup\Query\GetProductAttributeGroups;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Command\BulkDeleteCombinationCommand;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Command\DeleteCombinationCommand;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Command\GenerateProductCombinationsCommand;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Exception\BulkCombinationException;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Exception\CannotGenerateCombinationException;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Exception\CombinationException;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Exception\CombinationNotFoundException;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Query\GetCombinationIds;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Query\GetEditableCombinationsList;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Query\SearchCombinationsForAssociation;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\Query\SearchProductCombinations;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\QueryResult\CombinationForAssociation;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\QueryResult\CombinationListForEditing;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\QueryResult\ProductCombinationsCollection;
use PrestaShop\PrestaShop\Core\Domain\Product\Combination\ValueObject\CombinationId;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\ProductConstraintException;
use PrestaShop\PrestaShop\Core\Domain\Product\Stock\Exception\ProductStockConstraintException;
use PrestaShop\PrestaShop\Core\Domain\Shop\ValueObject\ShopConstraint;
use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Builder\FormBuilderInterface;
use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Handler\FormHandlerInterface;
use PrestaShop\PrestaShop\Core\Language\LanguageRepositoryInterface;
use PrestaShop\PrestaShop\Core\Search\Filters\ProductCombinationFilters;
use PrestaShopBundle\Controller\Admin\PrestaShopAdminController;
use PrestaShopBundle\Security\Attribute\AdminSecurity;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CombinationController extends PrestaShopAdminController
{
    /**
     * Options used for the number of combinations per page
     */
    private const COMBINATIONS_PAGINATION_OPTIONS = [ProductCombinationFilters::LIST_LIMIT, 20, 50, 100];

    public static function getSubscribedServices(): array
    {
        return parent::getSubscribedServices() + [
            ProductImagePathFactory::class => ProductImagePathFactory::class,
        ];
    }

    /**
     * @param Request $request
     * @param int $combinationId
     *
     * @return Response
     */
    #[AdminSecurity("is_granted('update', request.get('_legacy_controller'))")]
    public function editAction(
        Request $request,
        int $combinationId,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.builder.combination_form_builder')]
        FormBuilderInterface $combinationFormBuilder,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.combination_form_handler')]
        FormHandlerInterface $combinationFormHandler
    ): Response {
        $liteDisplaying = $request->query->has('liteDisplaying');
        try {
            $combinationForm = $combinationFormBuilder->getFormFor($combinationId);
        } catch (CombinationNotFoundException $e) {
            return $this->render(
                '@PrestaShop/Admin/Sell/Catalog/Product/Combination/not_found.html.twig',
                [],
                new Response('', Response::HTTP_NOT_FOUND)
            );
        }

        try {
            $combinationForm->handleRequest($request);

            $result = $combinationFormHandler->handleFor($combinationId, $combinationForm);

            if ($result->isSubmitted() && $result->isValid()) {
                $this->addFlash('success', $this->trans('Update successful', [], 'Admin.Notifications.Success'));

                return $this->redirectToRoute('admin_products_combinations_edit_combination', [
                    'combinationId' => $combinationId,
                    'liteDisplaying' => $liteDisplaying,
                ]);
            }
        } catch (Exception $e) {
            $this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
        }

        return $this->render('@PrestaShop/Admin/Sell/Catalog/Product/Combination/edit.html.twig', [
            'lightDisplay' => $liteDisplaying,
            'combinationForm' => $combinationForm->createView(),
        ]);
    }

    /**
     * @param Request $request
     * @param string $languageCode
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function searchCombinationsForAssociationAction(
        Request $request,
        string $languageCode,
        LanguageRepositoryInterface $langRepository,
    ): JsonResponse {
        $language = $langRepository->getOneByLocaleOrIsoCode($languageCode);
        if (null === $language) {
            return $this->json([
                'message' => sprintf(
                    'Invalid language code %s was used which matches no existing language in this shop.',
                    $languageCode
                ),
            ], Response::HTTP_BAD_REQUEST);
        }

        $shopId = $this->getShopContext()->getId();
        if (empty($shopId)) {
            $shopId = (int) $this->getConfiguration()->get('PS_SHOP_DEFAULT');
        }

        try {
            /** @var CombinationForAssociation[] $combinationProducts */
            $combinationProducts = $this->dispatchQuery(new SearchCombinationsForAssociation(
                $request->get('query', ''),
                $language->getId(),
                (int) $shopId,
                $request->get('filters', []),
                (int) $request->get('limit', 20)
            ));
        } catch (ProductConstraintException $e) {
            return $this->json([
                'message' => $e->getMessage(),
            ], Response::HTTP_BAD_REQUEST);
        }

        if (empty($combinationProducts)) {
            return $this->json([], Response::HTTP_NOT_FOUND);
        }

        return $this->json($this->formatCombinationProductsForAssociation($combinationProducts));
    }

    /**
     * @param Request $request
     * @param int $productId
     * @param int|null $shopId
     * @param int|null $languageId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function searchProductCombinationsAction(
        Request $request,
        int $productId,
        ?int $shopId,
        ?int $languageId,
    ): JsonResponse {
        $searchPhrase = $request->query->get('q', '');
        $shopConstraint = $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops();

        /** @var ProductCombinationsCollection $productCombinationsCollection */
        $productCombinationsCollection = $this->dispatchQuery(new SearchProductCombinations(
            $productId,
            $languageId ?: $this->getLanguageContext()->getId(),
            $shopConstraint,
            $searchPhrase,
            $request->query->getInt('limit', SearchProductCombinations::DEFAULT_RESULTS_LIMIT)
        ));

        return $this->json(['combinations' => $productCombinationsCollection->getProductCombinations()]);
    }

    /**
     * @param CombinationForAssociation[] $combinationsForAssociation
     *
     * @return array<array<string, mixed>>
     */
    protected function formatCombinationProductsForAssociation(array $combinationsForAssociation): array
    {
        $productsData = [];
        foreach ($combinationsForAssociation as $productForAssociation) {
            $productsData[] = [
                'product_id' => $productForAssociation->getProductId(),
                'unique_identifier' => $productForAssociation->getProductId() . '_' . $productForAssociation->getCombinationId(),
                'name' => $productForAssociation->getName(),
                'reference' => $productForAssociation->getReference(),
                'combination_id' => $productForAssociation->getCombinationId(),
                'image' => $productForAssociation->getImageUrl(),
                'quantity' => 1,
            ];
        }

        return $productsData;
    }

    /**
     * @param int $productId
     *
     * @return Response
     */
    #[AdminSecurity("is_granted('update', request.get('_legacy_controller'))")]
    public function bulkEditFormAction(
        Request $request,
        int $productId,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.builder.bulk_combination_form_builder')]
        FormBuilderInterface $bulkFormBuilder
    ): Response {
        $bulkCombinationForm = $bulkFormBuilder->getForm([], [
            'product_id' => $productId,
            'country_id' => $this->getCountryContext()->getId(),
            'shop_id' => $this->getShopContext()->getId(),
            'method' => Request::METHOD_PATCH,
        ]);
        $bulkCombinationForm->handleRequest($request);

        return $this->render('@PrestaShop/Admin/Sell/Catalog/Product/Combination/bulk.html.twig', [
            'bulkCombinationForm' => $bulkCombinationForm->createView(),
            'lightDisplay' => true,
        ]);
    }

    /**
     * @param Request $request
     * @param int $productId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('update', request.get('_legacy_controller'))")]
    public function bulkEditAction(
        Request $request,
        int $productId,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.builder.bulk_combination_form_builder')]
        FormBuilderInterface $bulkFormBuilder,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.bulk_combination_form_handler')]
        FormHandlerInterface $bulkFormHandler
    ): JsonResponse {
        $combinationIds = $request->request->get('combinationIds');
        if (!$combinationIds) {
            return $this->json([
                'error' => $this->getErrorMessageForException(new Exception(), [Exception::class => 'Missing combinationIds in request body']),
            ], Response::HTTP_BAD_REQUEST);
        }

        $combinationIds = json_decode($combinationIds);
        $errors = [];
        foreach ($combinationIds as $combinationId) {
            try {
                // PATCH request is required to avoid disabled fields to be forced with null values
                $bulkCombinationForm = $bulkFormBuilder->getFormFor($combinationId, [], [
                    'method' => Request::METHOD_PATCH,
                    'product_id' => $productId,
                    'country_id' => $this->getCountryContext()->getId(),
                    'shop_id' => $this->getShopContext()->getId(),
                ]);
            } catch (CombinationNotFoundException $e) {
                $errors[] = $this->getErrorMessageForException($e, $this->getErrorMessages());
                continue;
            }

            try {
                $bulkCombinationForm->handleRequest($request);
                $result = $bulkFormHandler->handleFor($combinationId, $bulkCombinationForm);

                if (!$result->isSubmitted()) {
                    return $this->json([
                        'error' => $this->getErrorMessageForException(new Exception(), [Exception::class => 'No submitted data']),
                    ], Response::HTTP_BAD_REQUEST);
                }

                if (!$result->isValid()) {
                    // it's the same form for all combinations, so if it is invalid for one, it will be invalid for all of them,
                    // so we return and break the loop
                    return $this->json([
                        'error' => $this->trans('Form contains invalid values', [], 'Admin.Notifications.Error'),
                        'formErrors' => $this->getFormErrorsForJS($bulkCombinationForm),
                    ], Response::HTTP_BAD_REQUEST);
                }
            } catch (CombinationException $e) {
                $errors[] = $this->getErrorMessageForException($e, $this->getErrorMessages());
            }
        }

        if (empty($errors)) {
            return $this->json(['success' => true]);
        }

        return $this->json(['errors' => $errors], Response::HTTP_BAD_REQUEST);
    }

    /**
     * Note: role must be hard coded because there is no route associated to this action therefore not
     * _legacy_controller request parameter.
     *
     * It can only be embedded into another view (does not have a route), it is included in this template:
     *
     * src/PrestaShopBundle/Resources/views/Admin/Sell/Catalog/Product/FormTheme/combination.html.twig
     *
     * @param int $productId
     *
     * @return Response
     */
    #[AdminSecurity("is_granted('read', 'AdminProducts')")]
    public function paginatedListAction(
        int $productId,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.builder.combination_list_form_builder')]
        FormBuilderInterface $listFormBuilder
    ): Response {
        $combinationsForm = $listFormBuilder->getForm();

        return $this->render('@PrestaShop/Admin/Sell/Catalog/Product/Combination/paginated_list.html.twig', [
            'productId' => $productId,
            'combinationLimitChoices' => self::COMBINATIONS_PAGINATION_OPTIONS,
            'combinationsLimit' => ProductCombinationFilters::LIST_LIMIT,
            'combinationsForm' => $combinationsForm->createView(),
            'isMultistoreActive' => $this->getShopContext()->isMultiShopEnabled(),
            'shopName' => $this->getShopContext()->getName(),
            'shopId' => $this->getShopContext()->getId(),
        ]);
    }

    /**
     * @param int $productId
     * @param int|null $shopId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function getAttributeGroupsAction(int $productId, ?int $shopId): JsonResponse
    {
        /** @var AttributeGroup[] $attributeGroups */
        $attributeGroups = $this->dispatchQuery(new GetProductAttributeGroups(
            $productId,
            $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops()
        ));

        return $this->json($this->formatAttributeGroupsForPresentation($attributeGroups));
    }

    /**
     * @param int|null $shopId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function getAllAttributeGroupsAction(?int $shopId): JsonResponse
    {
        /** @var AttributeGroup[] $attributeGroups */
        $attributeGroups = $this->dispatchQuery(new GetAttributeGroupList(
            $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops()
        ));

        return $this->json($this->formatAttributeGroupsForPresentation($attributeGroups));
    }

    /**
     * @param int $productId
     * @param ProductCombinationFilters $combinationFilters
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function getListAction(int $productId, ProductCombinationFilters $combinationFilters): JsonResponse
    {
        $combinationsList = $this->dispatchQuery(new GetEditableCombinationsList(
            $productId,
            $this->getLanguageContext()->getId(),
            ShopConstraint::shop($combinationFilters->getShopId()),
            $combinationFilters->getLimit(),
            $combinationFilters->getOffset(),
            $combinationFilters->getOrderBy(),
            $combinationFilters->getOrderWay(),
            $combinationFilters->getFilters()
        ));

        return $this->json($this->formatListForPresentation($combinationsList));
    }

    /**
     * @param int $productId
     * @param ProductCombinationFilters $filters
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('update', request.get('_legacy_controller'))")]
    public function getCombinationIdsAction(int $productId, ProductCombinationFilters $filters): JsonResponse
    {
        $combinationIds = $this->dispatchQuery(new GetCombinationIds(
            $productId,
            $filters->getShopConstraint(),
            $filters->getLimit(),
            $filters->getOffset(),
            $filters->getOrderBy(),
            $filters->getOrderWay(),
            $filters->getFilters()
        ));

        return $this->json(array_map(static function (CombinationId $combinationId): int {
            return $combinationId->getValue();
        }, $combinationIds));
    }

    /**
     * @param int $combinationId
     * @param int|null $shopId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('delete', request.get('_legacy_controller'))")]
    public function deleteAction(int $combinationId, ?int $shopId): JsonResponse
    {
        try {
            $this->dispatchCommand(new DeleteCombinationCommand(
                $combinationId,
                $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops()
            ));
        } catch (Exception $e) {
            return $this->json([
                'error' => $this->getErrorMessageForException($e, $this->getErrorMessages()),
            ], Response::HTTP_BAD_REQUEST);
        }

        return $this->json([
            'message' => $this->trans('Successful deletion', [], 'Admin.Notifications.Success'),
        ]);
    }

    /**
     * @param Request $request
     * @param int $productId
     * @param int|null $shopId
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
    public function bulkDeleteAction(Request $request, int $productId, ?int $shopId): JsonResponse
    {
        $combinationIds = $request->request->get('combinationIds');
        if (!$combinationIds) {
            return $this->json([
                'error' => $this->getErrorMessageForException(new Exception(), [Exception::class => 'Missing combinationIds in request body']),
            ], Response::HTTP_BAD_REQUEST);
        }

        try {
            $this->dispatchCommand(new BulkDeleteCombinationCommand(
                $productId,
                json_decode($combinationIds),
                $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops()
            ));
        } catch (Exception $e) {
            if ($e instanceof BulkCombinationException) {
                return $this->jsonBulkErrors($e);
            }

            return $this->json([
                'error' => $this->getErrorMessageForException($e, $this->getErrorMessages()),
            ], Response::HTTP_BAD_REQUEST);
        }

        return $this->json(['success' => true]);
    }

    /**
     * Format the bulk exception into an array of errors returned in a JsonResponse.
     *
     * @param BulkCombinationException $bulkCombinationException
     *
     * @return JsonResponse
     */
    private function jsonBulkErrors(BulkCombinationException $bulkCombinationException): JsonResponse
    {
        $errors = [];
        foreach ($bulkCombinationException->getBulkExceptions() as $productId => $productException) {
            $errors[] = $this->trans(
                'Error for combination %combination_id%: %error_message%',
                [
                    '%combination_id%' => $productId,
                    '%error_message%' => $this->getErrorMessageForException($productException, $this->getErrorMessages()),
                ],
                'Admin.Catalog.Notification'
            );
        }

        return $this->json(['errors' => $errors], Response::HTTP_BAD_REQUEST);
    }

    /**
     * @param int $productId
     * @param Request $request
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('update', request.get('_legacy_controller'))")]
    public function updateCombinationFromListingAction(
        int $productId,
        Request $request,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.builder.combination_list_form_builder')]
        FormBuilderInterface $listFormBuilder,
        #[Autowire(service: 'prestashop.core.form.identifiable_object.combination_list_form_handler')]
        FormHandlerInterface $listFormHandler
    ): JsonResponse {
        $combinationsListForm = $listFormBuilder->getForm([], [
            'method' => Request::METHOD_PATCH,
        ]);

        try {
            $combinationsListForm->handleRequest($request);
            $result = $listFormHandler->handleFor($productId, $combinationsListForm);

            if (!$result->isSubmitted()) {
                return $this->json(['errors' => $this->getFormErrorsForJS($combinationsListForm)], Response::HTTP_BAD_REQUEST);
            } elseif (!$result->isValid()) {
                return $this->json([
                    'errors' => $this->getFormErrorsForJS($combinationsListForm),
                    'formContent' => $this->renderView('@PrestaShop/Admin/Sell/Catalog/Product/Combination/combination_list_form.html.twig', [
                        'combinationsForm' => $combinationsListForm->createView(),
                    ]),
                ], Response::HTTP_BAD_REQUEST);
            }
        } catch (Exception $e) {
            return $this->json(
                ['errors' => [$this->getErrorMessageForException($e, $this->getErrorMessages())]],
                Response::HTTP_INTERNAL_SERVER_ERROR
            );
        }

        return $this->json([
            'message' => $this->trans('Update successful', [], 'Admin.Notifications.Success'),
        ]);
    }

    /**
     * @param int $productId
     * @param int|null $shopId
     * @param Request $request
     *
     * @return JsonResponse
     */
    #[AdminSecurity("is_granted('create', request.get('_legacy_controller')) && is_granted('update', request.get('_legacy_controller'))")]
    public function generateCombinationsAction(int $productId, ?int $shopId, Request $request): JsonResponse
    {
        $requestAttributeGroups = $request->request->all('attributes');
        $attributes = [];
        foreach ($requestAttributeGroups as $attributeGroupId => $requestAttributes) {
            $attributes[(int) $attributeGroupId] = array_map('intval', $requestAttributes);
        }

        try {
            /** @var CombinationId[] $combinationsIds */
            $combinationsIds = $this->dispatchCommand(new GenerateProductCombinationsCommand(
                $productId,
                $attributes,
                $shopId ? ShopConstraint::shop($shopId) : ShopConstraint::allShops()
            ));
        } catch (Exception $e) {
            return $this->json([
                'error' => [
                    $this->getErrorMessageForException($e, $this->getErrorMessages()),
                ],
            ], Response::HTTP_BAD_REQUEST);
        }

        return $this->json([
            'combination_ids' => array_map(function (CombinationId $combinationId) { return $combinationId->getValue(); }, $combinationsIds),
        ]);
    }

    /**
     * @param AttributeGroup[] $attributeGroups
     *
     * @return array<int, array<string, mixed>>
     */
    private function formatAttributeGroupsForPresentation(array $attributeGroups): array
    {
        $contextLangId = $this->getLanguageContext()->getId();

        $formattedGroups = [];
        foreach ($attributeGroups as $attributeGroup) {
            $attributes = [];
            /** @var Attribute $attribute */
            foreach ($attributeGroup->getAttributes() as $attribute) {
                $attributeNames = $attribute->getLocalizedNames();
                $attributeData = [
                    'id' => $attribute->getAttributeId(),
                    'name' => $attributeNames[$contextLangId] ?? reset($attributeNames),
                ];
                if (null !== $attribute->getColor()) {
                    $attributeData['color'] = $attribute->getColor();
                }
                if (null !== $attribute->getTextureFilePath()) {
                    $attributeData['texture'] = $attribute->getTextureFilePath();
                }
                $attributes[] = $attributeData;
            }

            $publicNames = $attributeGroup->getLocalizedPublicNames();
            $names = $attributeGroup->getLocalizedNames();
            $formattedGroups[] = [
                'id' => $attributeGroup->getAttributeGroupId(),
                'name' => $names[$contextLangId] ?? reset($names),
                'publicName' => $publicNames[$contextLangId] ?? reset($publicNames),
                'attributes' => $attributes,
            ];
        }

        return $formattedGroups;
    }

    /**
     * @param CombinationListForEditing $combinationListForEditing
     *
     * @return array<string, array<int, array<string,bool|int|string|float>>|int>
     */
    private function formatListForPresentation(CombinationListForEditing $combinationListForEditing): array
    {
        $data = [
            'combinations' => [],
            'total' => $combinationListForEditing->getTotalCombinationsCount(),
        ];

        $fallbackImageUrl = $this->getFallbackImageUrl();
        foreach ($combinationListForEditing->getCombinations() as $combination) {
            $data['combinations'][] = [
                'combination_id' => $combination->getCombinationId(),
                'is_selected' => false,
                'name' => $combination->getCombinationName(),
                'reference' => $combination->getReference(),
                'impact_on_price_te' => (string) $combination->getImpactOnPrice(),
                'quantity' => $combination->getQuantity(),
                'is_default' => $combination->isDefault(),
                'image_url' => $combination->getImageUrl() ?: $fallbackImageUrl,
                'eco_tax' => (string) $combination->getEcoTax(),
            ];
        }

        return $data;
    }

    /**
     * @return string
     */
    private function getFallbackImageUrl(): string
    {
        return $this->container->get(ProductImagePathFactory::class)->getNoImagePath(ProductImagePathFactory::IMAGE_TYPE_SMALL_DEFAULT);
    }

    /**
     * Gets an error by exception class and its code.
     *
     * @return array
     */
    private function getErrorMessages(): array
    {
        return [
            ProductConstraintException::class => [
                ProductConstraintException::INVALID_LOW_STOCK_THRESHOLD => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Low stock level', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
                ProductConstraintException::INVALID_LOW_STOCK_ALERT => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Low stock alert', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
                ProductConstraintException::INVALID_AVAILABLE_DATE => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Availability date', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
                ProductConstraintException::INVALID_MINIMAL_QUANTITY => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Minimum order quantity', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
            ],
            ProductStockConstraintException::class => [
                ProductStockConstraintException::INVALID_QUANTITY => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Quantity', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
                ProductStockConstraintException::INVALID_LOCATION => $this->trans(
                    'The %s field is invalid.',
                    [sprintf('"%s"', $this->trans('Stock location', [], 'Admin.Catalog.Feature'))],
                    'Admin.Notifications.Error'
                ),
            ],
            CombinationNotFoundException::class => $this->trans(
                'The object cannot be loaded (or found).',
                [],
                'Admin.Notifications.Error'
            ),
            CannotGenerateCombinationException::class => [
                CannotGenerateCombinationException::DIFFERENT_ATTRIBUTES_BETWEEN_SHOPS => $this->trans(
                    'To create combinations for all your stores, the selected attributes must be available on each of them.',
                    [],
                    'Admin.Notifications.Error'
                ),
            ],
        ];
    }
}
