<?php

namespace KupShop\ElninoBundle\View;

use KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper;
use KupShop\CatalogBundle\ProductList\MultiFetch;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\CatalogBundle\Util\ActiveCategory;
use KupShop\ElninoBundle\Translations\AbraModelsTranslation;
use KupShop\ElninoBundle\Translations\AbraScentsTranslation;
use KupShop\ElninoBundle\Util\ElninoMultiFetch;
use KupShop\I18nBundle\Translations\SectionsTranslation;
use KupShop\KupShopBundle\Exception\RedirectException;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\System\PathFinder;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use Query\Operator;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class ModelView extends View
{
    use RequestTrait;

    protected $template = 'product.tpl';

    /** @var \Product */
    private $product;

    /** @var ProductCollection */
    private $products;

    /** @var ActiveCategory */
    private $activeCategory;

    /** @var ProductWrapper */
    private $wrapper;

    private $modelID;

    private $modelOldID;

    private $model;

    /**
     * @var PathFinder
     */
    private $pathFinder;

    /** @var MultiFetch */
    protected $multiFetch;

    public function __construct(ActiveCategory $activeCategory, ProductWrapper $wrapper, PathFinder $pathFinder, MultiFetch $multiFetch)
    {
        $this->activeCategory = $activeCategory;
        $this->wrapper = $wrapper;
        $this->pathFinder = $pathFinder;
        $this->multiFetch = $multiFetch;
    }

    public function getHeaderVariables()
    {
        $header = parent::getHeaderVariables();

        if ($this->getSearchString()) {
            $header['searchString'] = $this->getSearchString();
        }

        return $header;
    }

    public function getBodyVariables()
    {
        $this->checkProductExist();
        $this->checkCorrectUrl($this->request);
        $this->product->fetchImages(3);

        $vars = parent::getBodyVariables();

        if ($this->search()) {
            $vars['search'] = $this->search();
        }

        $vars['product'] = $this->wrapper->setObject($this->getProduct());
        $vars['products'] = $this->products;

        $params = [];
        foreach ($vars['products'] as $id => $product) {
            foreach ($product['param'] as $id_param => $param) {
                $params[$id_param]['name'] = $param['name'];
                $params[$id_param]['figure'] = $param['figure'];
                $params[$id_param]['products'][$id] = $id;

                foreach ($param['values'] as $id_value => $param_value) {
                    $params[$id_param]['parameters'][$id_value] = $param_value['value'];
                }
                if (!in_array($id_param, [37, 38, 39, 18, 28])) {
                    foreach ($vars['products'] as $id_check => $product_check) {
                        if ($id_check != $id) {
                            if (empty($product_check['param'][$id_param]) || $product['param'][$id_param]['values'] != $product_check['param'][$id_param]['values']) {
                                $params[$id_param]['unique'] = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
        $vars['product']['param_list'] = $params;

        $campaigns = [];
        foreach ($this->products as $product) {
            $campaigns = array_merge($campaigns, $product->campaign_codes);
        }
        $vars['campaigns'] = $campaigns;

        $qb = sqlQueryBuilder()
            ->select('element, as1.name')
            ->from('abra_products_scents', 'aps')
            ->innerJoin('aps', 'abra_scents', 'as1', 'as1.id_abra = aps.id_scent')
            ->where(Operator::equals(['aps.id_model' => $this->getModelID()]))
            ->andWhere(
                \Query\Translation::coalesceTranslatedFields(
                    AbraScentsTranslation::class
                )
            )
            ->execute();
        $parameters = [];
        foreach ($qb as $param) {
            $parameters[$param['element']]['values'][] = $param['name'];
        }
        $vars['product']['param'] += $parameters;

        $vars['model'] = $this->getModel();

        $vars['serie'] = sqlQueryBuilder()->select('abs.*')
            ->from('abra_series', 'abs')
            ->leftJoin('abs', 'abra_models', 'abm', 'abm.id_serie = abs.id_abra')
            ->where(Operator::equals(['abm.id_abra' => $this->getModelID()]))
            ->execute()->fetch();

        $cotyPictureAbraID = sqlQueryBuilder()->select('api.id_abra')->from('products', 'p')
            ->innerJoin('p', 'abra_products', 'apr', 'apr.id_product=p.id')
            ->innerJoin('apr', 'abra_pictures', 'api', 'api.id_abra_product=apr.id_abra AND api.type>=21 AND api.type<=30')
            ->where(Operator::equals(['p.id_model' => $this->getModelID()]))
            ->setMaxResults(1)->execute()->fetchColumn(0);
        $vars['hasCotyPictures'] = !empty($cotyPictureAbraID);

        $vars['gpsrParamID'] = sqlQueryBuilder()->select('id_parameter')
            ->from('abra_parameters')->where('id_abra=82')
            ->setMaxResults(1)->execute()->fetchOne();

        return $vars;
    }

    public function getDeliveries()
    {
        return \DeliveryType::getDeliveries();
    }

    public function getSearchString()
    {
        if ($this->request->get('search') != null && trim($this->request->get('search')) != '') {
            $search = trim($this->request->get('search'));

            return $search;
        }

        return false;
    }

    public function search()
    {
        if ($this->getSearchString()) {
            $search = trim($this->getSearchString());

            $word = [];
            $word = preg_split('/[[:blank:]]+/', $search);

            if (count($word) > 0) {
                for ($i = 0; $i < count($word); $i++) {
                    if (trim($word[$i]) == '') {
                        unset($word[$i]);
                    }

                    $word[$i] = preg_quote($word[$i]);
                }
            }

            return $word;
        }

        return false;
    }

    public function getBreadcrumbs()
    {
        $returnNav = [];
        $navArray = null;
        $product = $this->getProduct();
        $model = $this->getModel();

        // kategorie vsech produktu modelu
        $sections = sqlQueryBuilder()
            ->select('DISTINCT ps.id_section')
            ->from('products_in_sections', 'ps')
            ->join('ps', 'sections', 's', 'ps.id_section = s.id')
            ->where(Operator::equals(['s.figure' => 'Y']))
            ->andWhere(Operator::inIntArray($this->products->getProductIds(), 'id_product'))
            ->orderBy('s.priority', 'DESC')
            ->addOrderBy('ps.deletable', 'DESC')
            ->execute()->fetchAll();

        // fallback
        if (empty($sections)) {
            $sections[] = [
                'id_section' => $model['section_id'],
            ];
        }

        foreach ($sections as $index => $row) {
            $navArray = getReturnNavigation($row['id_section'], 'PRODUCT', [$product->title]);

            if ($index == 0) {
                // Set opened menu section - first available section
                if ($this->activeCategory->loadCategoryId() == null) {
                    $this->activeCategory->setCategoryId($row['id_section']);
                }
            }

            $returnNav = array_merge($returnNav, $navArray);

            if ($this->activeCategory->loadCategoryId() == null) {
                $this->activeCategory->setCategoryId($row['id_section']);
            }
        }

        return $returnNav;
    }

    public function getDeliveryDays()
    {
        $days = sqlQueryBuilder()->select('MAX(time_days) as days')->from('delivery_type_delivery')->execute()->fetch();
        if ($days) {
            $days = ['min' => $days['days']];
        }

        if (findModule(\Modules::DELIVERY_PRICELIST)) {
            $priceList = ServiceContainer::getService(\KupShop\DeliveryPriceListBundle\DeliveryPriceCalculator::class);
            $countryContext = ServiceContainer::getService(\KupShop\KupShopBundle\Context\CountryContext::class);
            $days = $priceList->getDeliveryTime($countryContext->getActiveId());
        }

        return $days;
    }

    public function checkCorrectUrl(Request $request): void
    {
        $urlCorrect = path('kupshop_elnino_model_model', [
            'id' => $this->getModelOldID(),
            'name' => createScriptURL_Text($this->getProduct()->model_title),
        ]);

        $urlCurrent = parse_url($this->request->getRequestUri(), PHP_URL_PATH);

        if (strpos($urlCurrent, $urlCorrect) !== 0) {
            throw new RedirectException($urlCorrect);
        }
    }

    public function getModel()
    {
        if (!$this->model) {
            $this->model = sqlQueryBuilder()->select('abm.*, s.name as section, s.id as section_id, pr.name as producer, abs.name as serie, abcm.name as complement_model')
                ->from('abra_models', 'abm')
                ->leftJoin('abm', 'abra_series', 'abs', 'abm.id_serie = abs.id_abra')
                ->leftJoin('abm', 'abra_sections', 'absec', 'abm.id_section = absec.id_abra')
                ->leftJoin('abm', 'abra_complement_models', 'abcm', 'abm.id_complement_model = abcm.id_abra')
                ->leftJoin('absec', 'sections', 's', 'absec.id_section = s.id')
                ->leftJoin('abs', 'producers', 'pr', 'abs.id_producer = pr.id')
                ->where(Operator::equals(['abm.id_abra' => $this->getModelID()]))
                ->andWhere(Translation::coalesceTranslatedFields(
                    SectionsTranslation::class, ['name' => 'section'])
                )
                ->andWhere(Translation::coalesceTranslatedFields(
                    AbraModelsTranslation::class)
                )
                ->execute()->fetch();
        }

        return $this->model;
    }

    public function checkProductExist()
    {
        if (!$this->getProduct()) {
            throw new NotFoundHttpException('Product not found');
        }
    }

    public function getProduct()
    {
        if (!$this->product) {
            $productList = new \ProductList(false);

            if (findModule('products', 'showMax')) {
                $productList->andSpec(
                    function (QueryBuilder $qb) {
                        $qb->addSelect('LEAST(p.in_store, COALESCE(p.in_store_show_max, '.findModule('products', 'showMax').')) in_store');
                    }
                );
            }

            $productList->andSpec(function (QueryBuilder $qb) {
                $qb->andWhere(Operator::equals(['p.id_model' => $this->getModelID()]))
                    ->andWhere("p.figure IN ('Y', 'O')")
                    ->addSelect('p.old_kupshop_id as variation_id, p.parameters as parameters, 
                p.meta_keywords, p.meta_description, p.meta_title')
                    ->addSelect('p.sup_name, p.sup_addr, p.sup_contact');
            });

            $productList->fetchSections();
            $productList->fetchAdditionalImages(4);
            $productList->fetchParameters();
            $productList->fetchProducers();
            $productList->fetchProductOfSuppliersInStore();
            $products = $productList->getProducts();
            ElninoMultiFetch::fetchAdditionalData($products);
            $this->multiFetch->fetchCotyVideos($products);
            $this->products = $products;
            $this->product = $products->first();

            // aby se zobrazil model bez produktu (misto 404)
            if (!$this->product && $this->getModel()) {
                $this->product = new \Product();
                $this->product->model_title = $this->getModel()['short_title'];
                $this->product->model_short_title = $this->getModel()['short_title'];
                $this->product->title = $this->getModel()['short_title'];
                $this->product->visible = 'O';
                $this->product->fetchParameters();
            }

            // tohle je kvuli p.figure IN ('Y', 'O')
            $loop = 1;
            while (($this->product->visible != 'Y' || ($this->product->inStore <= 0 && $this->product->in_store_suppliers <= 0)) && $loop < $products->count()) {
                $this->product = $products->next();
                $loop++;
            }

            // Stalo se, ze produkt mel cenu 0 a zaroven mel sklad - sice mel figure = O, ale protoze
            // se fetchuji i produkty s figure O, tak se zobrazil + diky skladu se nabidl ke koupi s
            // nulovou cenou
            // To stejny obrazek.. pokud ma sklad, ale nema obrazek, tak se zobrazil :(
            foreach ($this->products as $key => $product) {
                if ($product->price_array['price_with_vat']->isZero()) {
                    $product->inStore = 0;
                    $product->prepareDeliveryText();
                }
                // nechceme zobrazovat produktu, ktere nemaji obrazek.. maji figure O, ale pokud
                // ma sklad, tak se ukazal
                if (empty($product->photos)) {
                    unset($this->products[$key]);
                }
            }
        }

        return $this->product;
    }

    public function getTitle()
    {
        return $this->getProduct()->title;
    }

    public function getWpjToolbar()
    {
        $arr = [
            'url' => getAdminUrl('products', ['ID' => $this->getModelID()]),
            'title' => 'Upravit produkt',
            'translateUrl' => getAdminUrl('list', [
                'type' => 'translateProducts',
                'iframe' => 1,
                'objectIDs' => $this->getModelID(),
            ]),
            'translateTitle' => 'Překlad produktu',
        ];

        return array_merge(parent::getWpjToolbar(), $arr);
    }

    public function setModelID($id)
    {
        $this->modelID = $id;
    }

    public function getModelID()
    {
        return $this->modelID;
    }

    public function setModelOldID($id)
    {
        $this->modelOldID = $id;
    }

    public function getModelOldID()
    {
        return $this->modelOldID;
    }
}
