<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

namespace ArtabanMarketplace\Controller;

use Thelia\Controller\Admin\ProductController as BaseController;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Event\FeatureProduct\FeatureProductDeleteEvent;
use Thelia\Core\Event\FeatureProduct\FeatureProductUpdateEvent;
use Thelia\Core\Event\MetaData\MetaDataCreateOrUpdateEvent;
use Thelia\Core\Event\MetaData\MetaDataDeleteEvent;
use Thelia\Core\Event\Product\ProductAddAccessoryEvent;
use Thelia\Core\Event\Product\ProductAddCategoryEvent;
use Thelia\Core\Event\Product\ProductAddContentEvent;
use Thelia\Core\Event\Product\ProductCloneEvent;
use Thelia\Core\Event\Product\ProductCombinationGenerationEvent;
use Thelia\Core\Event\Product\ProductCreateEvent;
use Thelia\Core\Event\Product\ProductDeleteAccessoryEvent;
use Thelia\Core\Event\Product\ProductDeleteCategoryEvent;
use Thelia\Core\Event\Product\ProductDeleteContentEvent;
use Thelia\Core\Event\Product\ProductDeleteEvent;
use Thelia\Core\Event\Product\ProductEvent;
use Thelia\Core\Event\Product\ProductSetTemplateEvent;
use Thelia\Core\Event\Product\ProductToggleVisibilityEvent;
use Thelia\Core\Event\Product\ProductUpdateEvent;
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementCreateEvent;
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementDeleteEvent;
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\HttpFoundation\JsonResponse;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Core\Template\Loop\Document;
use Thelia\Core\Template\Loop\Image;
use Thelia\Form\BaseForm;
use Thelia\Form\Definition\AdminForm;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Form\ProductModificationForm;
use Thelia\Model\AccessoryQuery;
use Thelia\Model\AttributeAv;
use Thelia\Model\AttributeAvQuery;
use Thelia\Model\AttributeQuery;
use Thelia\Model\CategoryQuery;
use Thelia\Model\Content;
use Thelia\Model\ContentQuery;
use Thelia\Model\Country;
use Thelia\Model\Currency;
use Thelia\Model\CurrencyQuery;
use Thelia\Model\Feature;
use Thelia\Model\FeatureProductQuery;
use Thelia\Model\FeatureQuery;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Model\FolderQuery;
use Thelia\Model\MetaData;
use Thelia\Model\MetaDataQuery;
use Thelia\Model\Product;
use Thelia\Model\ProductAssociatedContentQuery;
use Thelia\Model\ProductDocument;
use Thelia\Model\ProductDocumentQuery;
use Thelia\Model\ProductImageQuery;
use Thelia\Model\ProductPrice;
use Thelia\Model\ProductPriceQuery;
use Thelia\Model\ProductQuery;
use Thelia\Model\ProductSaleElements;
use Thelia\Model\ProductSaleElements as ProductSaleElementsModel;
use Thelia\Model\ProductSaleElementsProductDocument;
use Thelia\Model\ProductSaleElementsProductDocumentQuery;
use Thelia\Model\ProductSaleElementsProductImage;
use Thelia\Model\ProductSaleElementsProductImageQuery;
use Thelia\Model\ProductSaleElementsQuery;
use Thelia\Model\TaxRuleQuery;
use Thelia\TaxEngine\Calculator;
use Thelia\Type\BooleanOrBothType;

/**
 * Description of ProductController
 *
 * @author LENGY
 */
class ProductController extends BaseController {

    protected $currentRouter = "router.ArtabanMarketplace";

    protected function renderEditionTemplate() {
        return $this->render('seller-product-edit', $this->getEditionArguments());
    }

    protected function redirectToEditionTemplate() {
        return $this->generateRedirectFromRoute("ArtabanMarketplace.admin.products.view", $this->getEditionArguments());
    }

    protected function redirectToListTemplate() {
        return $this->generateRedirectFromRoute(
                        'ArtabanMarketplace.seller.admin.catalog', [
                    'category_id' => $this->getCategoryId(),
                    'page' => $this->getRequest()->get('page', 1)
                        ]
        );
    }

    /**
     * Change a product sale element
     *
     * @param BaseForm $changeForm
     *
     * @return mixed|null|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response|Response
     */
    protected function processProductSaleElementUpdate($changeForm) {
        // Check current user authorization
        if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) {
            return $response;
        }

        try {
            // Check the form against constraints violations
            $form = $this->validateForm($changeForm, "POST");

            // Get the form field values
            $data = $form->getData();

            if (is_array($data['product_sale_element_id'])) {
                // Common fields
                $tmp_data = array(
                    'tax_rule' => $data['tax_rule'],
                    'currency' => $data['currency'],
                    'use_exchange_rate' => $data['use_exchange_rate'],
                );

                $count = count($data['product_sale_element_id']);

                for ($idx = 0; $idx < $count; $idx++) {
                    $tmp_data['product_sale_element_id'] = $pse_id = $data['product_sale_element_id'][$idx];
                    $tmp_data['reference'] = $data['reference'][$idx];
                    $tmp_data['price'] = $data['price'][$idx];
                    $tmp_data['weight'] = $data['weight'][$idx];
                    $tmp_data['quantity'] = $data['quantity'][$idx];
                    $tmp_data['sale_price'] = $data['sale_price'][$idx];
                    $tmp_data['onsale'] = isset($data['onsale'][$idx]) ? 1 : 0;
                    $tmp_data['isnew'] = isset($data['isnew'][$idx]) ? 1 : 0;
                    $tmp_data['isdefault'] = $data['default_pse'] == $pse_id;
                    $tmp_data['ean_code'] = $data['ean_code'][$idx];

                    $this->processSingleProductSaleElementUpdate($tmp_data);
                }
            } else {
                // No need to preprocess data
                $this->processSingleProductSaleElementUpdate($data);
            }

            // If we have to stay on the same page, do not redirect to the successUrl, just redirect to the edit page again.
            if ($this->getRequest()->get('save_mode') == 'stay') {
                return $this->redirectToEditionTemplate();
            }

            // Redirect to the success URL
            return $this->generateSuccessRedirect($changeForm);
        } catch (FormValidationException $ex) {
            // Form cannot be validated
            $error_msg = $this->createStandardFormValidationErrorMessage($ex);
        } catch (\Exception $ex) {
            // Any other error
            $error_msg = $ex->getMessage();
        }

        $this->setupFormErrorContext(
                $this->getTranslator()->trans("ProductSaleElement modification"), $error_msg, $changeForm, $ex
        );

        // At this point, the form has errors, and should be redisplayed.
        return $this->renderEditionTemplate();
    }

    /**
     * A a new combination to a product
     */
    public function deleteProductSaleElementAction() {
        // Check current user authorization
        if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) {
            return $response;
        }

        $event = new ProductSaleElementDeleteEvent(
                $this->getRequest()->get('product_sale_element_id', 0), $this->getCurrentEditionCurrency()->getId()
        );

        try {
            $this->dispatch(TheliaEvents::PRODUCT_DELETE_PRODUCT_SALE_ELEMENT, $event);
        } catch (\Exception $ex) {
            // Any error
            return $this->errorPage($ex);
        }

        return $this->redirectToEditionTemplate();
    }

    /**
     * Build combinations from the combination output builder
     */
    public function buildCombinationsAction() {
        // Check current user authorization
        if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) {
            return $response;
        }

        $changeForm = $this->createForm(AdminForm::PRODUCT_COMBINATION_GENERATION);

        try {
            // Check the form against constraints violations
            $form = $this->validateForm($changeForm, "POST");

            // Get the form field values
            $data = $form->getData();

            // Rework attributes_av array, to build an array which contains all combinations,
            // in the form combination[] = array of combination attributes av IDs
            //
            // First, create an array of attributes_av ID in the form $attributes_av_list[$attribute_id] = array of attributes_av ID
            // from the list of attribute_id:attributes_av ID from the form.
            $combinations = $attributes_av_list = $tmp = array();

            foreach ($data['attribute_av'] as $item) {
                list($attribute_id, $attribute_av_id) = explode(':', $item);

                if (!isset($attributes_av_list[$attribute_id])) {
                    $attributes_av_list[$attribute_id] = array();
                }

                $attributes_av_list[$attribute_id][] = $attribute_av_id;
            }

            // Next, recursively combine array
            $this->combine($attributes_av_list, $combinations, $tmp);

            // Create event
            $event = new ProductCombinationGenerationEvent(
                    $this->getExistingObject(), $data['currency'], $combinations
            );

            $event
                    ->setReference($data['reference'] == null ? '' : $data['reference'])
                    ->setPrice($data['price'] == null ? 0 : $data['price'])
                    ->setWeight($data['weight'] == null ? 0 : $data['weight'])
                    ->setQuantity($data['quantity'] == null ? 0 : $data['quantity'])
                    ->setSalePrice($data['sale_price'] == null ? 0 : $data['sale_price'])
                    ->setOnsale($data['onsale'] == null ? false : $data['onsale'])
                    ->setIsnew($data['isnew'] == null ? false : $data['isnew'])
                    ->setEanCode($data['ean_code'] == null ? '' : $data['ean_code'])
            ;

            $this->dispatch(TheliaEvents::PRODUCT_COMBINATION_GENERATION, $event);

            // Log object modification
            $this->adminLogAppend(
                    $this->resourceCode, AccessManager::CREATE, sprintf(
                            "Combination generation for product reference %s", $event->getProduct()->getRef()
                    ), $event->getProduct()->getId()
            );

            // Redirect to the success URL
            return $this->generateSuccessRedirect($changeForm);
        } catch (FormValidationException $ex) {
            // Form cannot be validated
            $error_msg = $this->createStandardFormValidationErrorMessage($ex);
        } catch (\Exception $ex) {
            // Any other error
            $error_msg = $ex->getMessage();
        }

        $this->setupFormErrorContext(
                $this->getTranslator()->trans("Combination builder"), $error_msg, $changeForm, $ex
        );

        // At this point, the form has errors, and should be redisplayed.
        return $this->renderEditionTemplate();
    }

    /**
     * A a new combination to a product
     */
    public function addProductSaleElementAction() {
        // Check current user authorization
        if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) {
            return $response;
        }

        $event = new ProductSaleElementCreateEvent(
                $this->getExistingObject(), $this->getRequest()->get('combination_attributes', array()), $this->getCurrentEditionCurrency()->getId()
        );

        try {
            $this->dispatch(TheliaEvents::PRODUCT_ADD_PRODUCT_SALE_ELEMENT, $event);
        } catch (\Exception $ex) {
            // Any error
            return $this->errorPage($ex);
        }

        return $this->redirectToEditionTemplate();
    }

    /**
     * Change product template for a given product.
     *
     * @param  int                                              $productId
     * @return mixed|\Symfony\Component\HttpFoundation\Response
     */
    public function setProductTemplateAction($productId) {
        // Check current user authorization
        if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) {
            return $response;
        }

        $product = ProductQuery::create()->findPk($productId);

        if ($product != null) {
            $template_id = intval($this->getRequest()->get('template_id', 0));

            $this->dispatch(
                    TheliaEvents::PRODUCT_SET_TEMPLATE, new ProductSetTemplateEvent($product, $template_id, $this->getCurrentEditionCurrency()->getId())
            );
        }

        return $this->redirectToEditionTemplate();
    }

    /**
     * Attributes ajax tab loading
     */
    public function loadAttributesAjaxTabAction() {
        return $this->render(
                        'ajax/seller-product-attributes-tab', array(
                    'product_id' => $this->getRequest()->get('product_id', 0),
                        )
        );
    }

    /**
     * Update product attributes and features
     *
     * @param int $productId
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function updateAttributesAndFeaturesAction($productId) {
        $product = ProductQuery::create()->findPk($productId);

        if ($product != null) {
            $featureTemplate = FeatureTemplateQuery::create()->filterByTemplateId($product->getTemplateId())->find();

            if ($featureTemplate !== null) {
                // Get all features for the template attached to this product
                $allFeatures = FeatureQuery::create()
                        ->filterByFeatureTemplate($featureTemplate)
                        ->find();

                $updatedFeatures = array();

                // Update all features values, starting with feature av. values
                $featureValues = $this->getRequest()->get('feature_value', array());

                foreach ($featureValues as $featureId => $featureValueList) {
                    // Delete all features av. for this feature.
                    $event = new FeatureProductDeleteEvent($productId, $featureId);

                    $this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);

                    // Add then all selected values
                    foreach ($featureValueList as $featureValue) {
                        $event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue);

                        $this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);
                    }

                    $updatedFeatures[] = $featureId;
                }

                // Update then features text values
                $featureTextValues = $this->getRequest()->get('feature_text_value', array());

                foreach ($featureTextValues as $featureId => $featureValue) {
                    // Check if a FeatureProduct exists for this product and this feature (for another lang)
                    $freeTextFeatureProduct = FeatureProductQuery::create()
                            ->filterByProductId($productId)
                            ->filterByFreeTextValue(true)
                            ->findOneByFeatureId($featureId);

                    // If no corresponding FeatureProduct exists AND if the feature_text_value is empty, do nothing
                    if (is_null($freeTextFeatureProduct) && empty($featureValue)) {
                        continue;
                    }

                    $event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue, true);
                    $event->setLocale($this->getCurrentEditionLocale());

                    $this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);

                    $updatedFeatures[] = $featureId;
                }

                // Delete features which don't have any values
                /** @var Feature $feature */
                foreach ($allFeatures as $feature) {
                    if (!in_array($feature->getId(), $updatedFeatures)) {
                        $event = new FeatureProductDeleteEvent($productId, $feature->getId());

                        $this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);
                    }
                }
            }
        }

        // If we have to stay on the same page, do not redirect to the successUrl,
        // just redirect to the edit page again.
        if ($this->getRequest()->get('save_mode') == 'stay') {
            return $this->redirectToEditionTemplate();
        }

        // Redirect to the category/product list
        return $this->redirectToListTemplate();
    }

}
