<?php

namespace KupShop\StoresBundle\Admin\lists;

use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\AdminBundle\AdminList\FiltersStorage;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use KupShop\KupShopBundle\Util\LoggingContext;
use KupShop\ProductsBatchesBundle\Util\ProductsBatchesUtil;
use KupShop\StoresBundle\Query\StoresQuery;
use KupShop\StoresBundle\Utils\StoresInStore;
use Query\Operator;
use Query\QueryBuilder;

class ProductsListBase extends BaseList
{
    use \AdminListSortable;
    use FiltersStorage;

    protected $template = 'list/storesProducts.tpl';
    protected $showImages = 0;
    protected $tableName = 'stores_items';
    protected ?string $tableAlias = 'si';

    protected $tableDef = [
        'id' => 'si.id',
        'fields' => [
            'store_name' => ['translate' => true, 'field' => 'store_name', 'spec' => 'store_name', 'type' => 'stores', 'visible' => 'N', 'type_id' => 'si.id_store', 'fieldType' => BaseList::TYPE_STRING],
            'product' => ['translate' => true, 'field' => 'product_title', 'size' => 4, 'type' => 'product', 'type_id' => 'si.id_product',   'render' => 'renderProductTitle'],
            'variation_title' => ['translate' => true, 'visible' => 'N', 'field' => 'variation_title', 'spec' => 'variation_title'],
            'number' => ['translate' => true, 'field' => 'id_product', 'type' => 'product', 'type_id' => 'si.id_product', 'render' => 'renderProductID'],
            'code' => ['translate' => true, 'field' => 'code', 'spec' => 'code'],
            'ean' => ['translate' => true, 'field' => 'ean', 'spec' => 'ean'],
            'quantity' => ['translate' => true, 'field' => 'quantity', 'render' => 'renderFloat', 'size' => 1],
            'in_order_quantity' => ['translate' => true, 'spec' => 'in_order_quantity', 'field' => 'in_order_quantity', 'size' => 0.7, 'visible' => 'Y'],
            'min_quantity' => ['translate' => true, 'visible' => 'N', 'field' => 'min_quantity', 'size' => 0.7],
            'quantity_total' => ['translate' => true, 'field' => 'quantity_total', 'spec' => 'quantity_total', 'render' => 'renderFloat', 'size' => 1],
            'delete' => ['translate' => true, 'visible' => 'N', 'render' => 'renderDelete'],
        ],
        'class' => 'getRowClass',
    ];

    public function customizeTableDef($tableDef)
    {
        $tableDef = parent::customizeTableDef($tableDef);

        if (findModule(\Modules::PRODUCTS_BATCHES)) {
            $tableDef['fields']['quantity']['field'] = 'batch_quantity';
            $tableDef['fields']['batch'] = ['translate' => true, 'field' => 'batch_code', 'render' => 'renderBatch'];
        }
        if (getVal('inStore') == 'inStore') {
            if (findModule(\Modules::PRODUCTS_BATCHES)) {
                $tableDef['fields']['batch']['visible'] = 'Y';
            }
            $tableDef['fields']['delete']['visible'] = 'Y';
        }

        $tableDef['fields']['product']['spec'] = function (QueryBuilder $qb) {
            $qb->leftJoin('si', 'products_variations', 'pv', 'pv.id = si.id_variation')
               ->addSelect('p.title as product_title')
               ->addSelect('pv.title as variation_title');
        };

        $tableDef['fields']['variation_title']['spec'] = function (QueryBuilder $qb) {
            $qb->leftJoin('si', 'products_variations', 'pv', 'pv.id = si.id_variation')
                ->addSelect('IFNULL(pv.title,"") as variation_title');
        };

        $tableDef['fields']['store_name']['spec'] = function (QueryBuilder $qb) {
            $qb->innerJoin('si', 'stores', 's', 's.id=si.id_store')
                ->addSelect('s.name as store_name');
        };

        $tableDef['fields']['ean']['spec'] = function (QueryBuilder $qb) {
            $qb->leftJoin('si', 'products_variations', 'pv', 'pv.id = si.id_variation')
               ->addSelect('COALESCE(pv.ean, p.ean) as ean');
        };

        $tableDef['fields']['code']['spec'] = function (QueryBuilder $qb) {
            $qb->leftJoin('si', 'products_variations', 'pv', 'pv.id = si.id_variation')
               ->addSelect('COALESCE(pv.code, p.code) as code');
        };

        $tableDef['fields']['in_order_quantity']['spec'] = function (QueryBuilder $qb) {
            $ordersQuantity = sqlQueryBuilder()
               ->select('os.id_store, oi.id_product', 'oi.id_variation', 'SUM(pieces) in_order_quantity')
               ->from('order_stores', 'os')
               ->leftJoin('os', 'orders', 'o', 'os.id_order = o.id')
               ->leftJoin('o', 'order_items', 'oi', 'oi.id_order = o.id')
               ->andWhere(\Query\Order::notPackedOrders())
               ->groupBy('os.id_store, oi.id_product', 'oi.id_variation');
            $qb->addSelect('in_order_quantity')->leftJoinSubQuery('si', $ordersQuantity, 'soq', 'si.id_store=soq.id_store AND soq.id_product = si.id_product AND (soq.id_variation <=> si.id_variation)');
        };

        $tableDef['fields']['quantity_total']['spec'] = function (QueryBuilder $qb) {
            $quantityTotalSubQuery = sqlQueryBuilder()
                ->select('SUM(soqt.quantity) quantity_total')
                ->from('stores_items', 'soqt')
                ->where('soqt.id_product = si.id_product AND (soqt.id_variation <=> si.id_variation)');
            $qb->addSubselect($quantityTotalSubQuery, 'quantity_total');
        };

        return $tableDef;
    }

    public function renderDelete($values)
    {
        $url = $this->getListUrl()."&acn=delete&delete[id_product]={$values['id_product']}&delete[id_variation]={$values['id_variation']}";

        if (findModule(\Modules::PRODUCTS_BATCHES)) {
            $url .= "&delete[id_batch]={$values['batch_id']}";
        }

        return HTML::create('a')
            ->attr('href', $url)
            ->attr('onclick', 'return confirm(\'Opravdu smazat?\')')
            ->tag('i')
                ->class('glyphicon glyphicon-remove')
                ->end();
    }

    private function getDefaultListUrl()
    {
        return $this->getListUrl().'&showOld=1&inStore=inStore';
    }

    private function getListUrl()
    {
        $url = '?s=list.php&type=storesProducts';
        if (getVal('storeID')) {
            $url .= '&storeID='.getVal('storeID');
        }

        return $url;
    }

    public function get_vars()
    {
        $vars = parent::get_vars();

        $storeID = getVal('storeID');
        $store = sqlQueryBuilder()
            ->select('id, name')
            ->from('stores')
            ->where(Operator::equals(['id' => $storeID]))
            ->execute()->fetch();

        $vars['body']['store'] = $store;

        $inStore = getVal('inStore');
        $vars['body']['inStore'] = $inStore;

        return $vars;
    }

    public function getRowClass($values)
    {
        $class = '';
        $in_store_field = $this->tableDef['fields']['quantity']['field'];
        if ($values[$in_store_field] < 0) {
            $class .= ' danger';
        }

        if ($this->showImages == '1') {
            $class .= ' product-list-thumbnail';
        }

        return $class;
    }

    public function getFilters()
    {
        $filters = [];

        if (findModule(\Modules::PRODUCERS)) {
            $filters['IDpr'] = [
                'title' => 'Výrobce',
                'name' => 'p2.name',
                'field' => 'p.producer',
                'from' => 'LEFT JOIN producers p2 ON p.producer=p2.id',
                'leftJoin' => [
                    'fromAlias' => 'p',
                    'table' => 'producers',
                    'alias' => 'p2',
                    'condition' => 'p.producer=p2.id',
                ],
            ];
        }

        return $filters;
    }

    public function getFiltersData(QueryBuilder $qb, $filters)
    {
        $filterValues = [];
        foreach ($filters as $name => $filter) {
            $choiced = false;
            if (getVal($name, null, '0') == '0') {
                $choiced = true;
            }
            $values = [
                '0' => [
                    'name' => $filter['title'],
                    'choiced' => $choiced,
                ],
            ];

            $from = getVal('from', $filter);
            $leftJoin = getVal('leftJoin', $filter);
            $nameField = getVal('name', $filter, $filter['field']);
            $orderField = getVal('order', $filter, 'name');

            $qb2 = clone $qb;

            $qb2->resetQueryPart('select');
            $qb2->select('DISTINCT '.$filter['field'].' as value', $nameField.' as name')
                ->leftJoin($leftJoin['fromAlias'], $leftJoin['table'], $leftJoin['alias'], $leftJoin['condition'])
                ->orderBy($orderField)
                ->setMaxResults(500);

            $qb2->andWhere(StoresQuery::addStoresInStoreAmounts([getVal('storeID')]));

            $storeID = getVal('storeID');
            if (findModule(\Modules::PRODUCTS_BATCHES) && $storeID != 1) {
                $qb2->addSelect(\KupShop\ProductsBatchesBundle\Query\BatchesQuery::joinStoreBatches());
            }

            $SQL = $qb2->execute();
            while (($row = sqlFetchAssoc($SQL)) !== false) {
                $choiced = false;
                if (getVal($name, null, '0') == $row['value']) {
                    $choiced = true;
                }
                $values[$row['value']]['name'] = $row['name'];
                $values[$row['value']]['choiced'] = $choiced;
            }
            $filterValues[$filter['title']] = $values;
        }

        return $filterValues;
    }

    public function renderBatch($values, $column)
    {
        $val = $this->getListRowValue($values, $column['field']);

        return HTML::create('span')->tag('abbr')
            ->attr('title', $values['batch_expiry'])->text($val);
    }

    public function renderProductTitle($values, $column)
    {
        $label = $this->getListRowValue($values, $column['field']);
        $ret[] = HTML::create('span')->text($label);
        $label = $this->getListRowValue($values, 'variation_title');
        if ($label) {
            $ret[] = HTML::create('span')->class('help-block')->text($label);
        }

        return $ret;
    }

    public function renderProductID($values, $column)
    {
        $label = $this->getListRowValue($values, $column['field']);
        $ret = "{$label}";
        $label = $this->getListRowValue($values, 'id_variation');
        if ($label) {
            $ret .= " / {$label}";
        }

        return $ret;
    }

    public function renderImage($values, $column)
    {
        $id = $this->getListRowValue($values, 'id');
        $SQL = sqlQuery('SELECT ph.id, ph.source, ph.image_2, php.show_in_lead
					FROM '.getTableName('photos').' AS ph, '.getTableName('photos_products_relation')." AS php
					WHERE ph.id=php.id_photo AND php.id_product='".$id."' AND php.show_in_lead='Y'");

        foreach ($SQL as $row) {
            $img = getImage($row['id'], $row['image_2'], $row['source'], 4);
        }

        $ret = $this->renderProductTitle($values, $column);
        $img_html = HTML::create('img')->class('img img-rounded');
        global $cfg;
        if (empty($img)) {
            $img_html->attr('src', '/admin/static/images/no-image.png');
        } else {
            $img_html->attr('src', $this->getUrlFinder()->staticUrl($img['source']));
        }
        array_unshift($ret, $img_html);

        return $ret;
    }

    public function showImages()
    {
        $this->showImages = getVal('products_list_images', $_COOKIE, false);
        if ($this->showImages == 0 && getVal('image') == '1') {
            setcookie('products_list_images', '1');
            $this->showImages = 1;
        }
        if ($this->showImages == 1 && getVal('image') == '0') {
            setcookie('products_list_images', '0');
            $this->showImages = 0;
        }

        if ($this->showImages == '1') {
            $this->tableDef['fields']['Zboží']['render'] = 'renderImage';
        }
    }

    protected function handleDelete()
    {
        $delete = getVal('delete');
        $storeId = getVal('storeID');

        sqlGetConnection()->transactional(function () use ($delete, $storeId) {
            $where = ['id_product' => $delete['id_product'],
                'id_variation' => empty($delete['id_variation']) ? null : $delete['id_variation'],
                'id_store' => $storeId, ];

            $storeItem = sqlQueryBuilder()->select('*')->forUpdate()
                ->from('stores_items', 'si')
                ->where(Operator::equalsNullable($where))
                ->execute()->fetchAssociative();

            $toRemove = $storeItem['quantity'];

            if (findModule(\Modules::PRODUCTS_BATCHES)) {
                $batches = json_decode($storeItem['custom_data'], true)['batch_numbers'] ?? [];

                if (empty($delete['id_batch'])) {
                    $toRemove -= array_sum(array_filter($batches, function ($k) {return $k; }, ARRAY_FILTER_USE_KEY));
                } else {
                    /**
                     * @var ProductsBatchesUtil $batchesUtil
                     */
                    $batchesUtil = ServiceContainer::getService(ProductsBatchesUtil::class);

                    $toRemove = $batches[$delete['id_batch']] ?? 0;

                    $batchesUtil->addBatchesToCustomData('stores_items', $where, [$delete['id_batch'] => -$toRemove]);
                }
            }

            $storesInStore = ServiceContainer::getService(StoresInStore::class);

            if ($toRemove >= $storeItem['quantity']) {
                sqlQueryBuilder()->delete('stores_items')
                    ->where(Operator::equalsNullable($where))
                    ->execute();
            } else {
                $storeItem['quantity'] = -$toRemove;
                ServiceContainer::getService(LoggingContext::class)->activateEdit(function () use ($storesInStore, $storeItem) {
                    $storesInStore->updateStoreItem($storeItem);
                });
            }
        });

        redirect($this->getDefaultListUrl());
    }

    public function getQuery()
    {
        $storeID = getVal('storeID');

        $qb = sqlQueryBuilder()
        ->select('si.*')
        ->from($this->tableName, $this->tableAlias)
        ->leftJoin('si', 'products', 'p', 'p.id=si.id_product');

        if ($storeID) {
            $qb->andWhere(Operator::equals(['si.id_store' => $storeID]));
        }
        if ($variationId = getVal('IDv')) {
            $qb->andWhere(Operator::equals(['si.id_variation' => $variationId]));
        }
        if ($productId = getVal('IDp')) {
            $qb->andWhere(Operator::equals(['si.id_product' => $productId]));
        }

        $qb->groupBy('si.id_store, si.id_product, si.id_variation');

        if (findModule(\Modules::PRODUCTS_BATCHES)) {
            $qb->addSelect(\KupShop\ProductsBatchesBundle\Query\BatchesQuery::joinStoreBatches());
            $qb->addSelect('pb.id batch_id');
            $qb->addGroupBy('pb.id');
        }

        $inStore = getVal('inStore', null, 'all');
        if ($inStore == 'inStore') {
            $qb->andWhere('si.quantity > 0');
        }
        if ($inStore == 'missing') {
            $qb->andWhere('si.quantity < 0');
        }

        $code = getVal('code');
        if (!empty($code)) {
            $code = trim($code);
            $code = "%{$code}%";
            $mapping['p.code'] = $code;
            if (findModule('products_variations', 'variationCode')) {
                $mapping['pv.code'] = $code;
            }
            if (findModule(\Modules::PRODUCTS_SUPPLIERS)) {
                $qb->leftJoin('p', 'products_of_suppliers', 'pofs', 'p.id = pofs.id_product');
                $mapping['pofs.code'] = $code;
            }
            $qb->andWhere(Operator::like($mapping, 'OR'));
        }

        $ean = getVal('ean');
        if (!empty($ean)) {
            $ean = trim($ean);
            $qb->andWhere('p.ean LIKE :eanParameter OR pv.ean LIKE :eanParameter')
                ->setParameter('eanParameter', "%{$ean}%");
        }

        $title = getVal('title');
        if (!empty($title)) {
            $search = get_search_query($title, [['field' => 'p.title', 'match' => 'both']]);
            $qb->andWhere($search['where']);

            foreach ($search['data'] ?? [] as $title => $data) {
                $qb->setParameter($title, $data);
            }
        }

        $IDpr = getVal('IDpr');
        if (!empty($IDpr)) {
            $IDpr = trim($IDpr);
            $qb->andWhere('prod2.producer=:idProducer')
                ->setParameter('idProducer', "{$IDpr}");
        }
        $this->showImages();

        return [
            'qb' => $qb,
            'showImages' => $this->showImages,
            'url' => $_SERVER['REQUEST_URI'],
        ];
    }
}

if (empty($subclass)) {
    class StoresProductsList extends ProductsListBase
    {
    }

    return StoresProductsList::class;
}
