<?php

namespace Admin\Lists;

use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\AdminBundle\AdminList\FiltersStorage;
use KupShop\AdminBundle\Util\ProductListFilter;
use KupShop\CatalogBundle\Query\Search;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use Query\Operator;
use Query\QueryBuilder;

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

    protected $template = 'list/products.tpl';

    protected $showMassEdit = true;
    protected $tableName = 'products';
    protected ?string $tableAlias = 'p';

    protected $tableDef = [
        'id' => 'p.id',
        'fields' => [
            'photo' => ['field' => 'p.title', 'size' => '80px', 'render' => 'renderImage', 'visible' => 'N', 'translate' => true],
            'title' => ['translate' => true, 'field' => 'p.title', 'size' => 4, 'type' => 'products', 'spec' => 'p.title', 'fieldType' => BaseList::TYPE_STRING],
            'productNumber' => ['translate' => true, 'field' => 'p.id'],
            'code' => ['translate' => true, 'field' => 'p.code'],
            'campaign' => ['translate' => true, 'field' => 'p.campaign', 'spec' => 'p.campaign', 'render' => 'renderCampaign', 'class' => 'columnCampaigns product-campaigns', 'fieldType' => BaseList::TYPE_LIST_MULTISELECT],
            'price' => ['translate' => true, 'field' => 'p.price', 'spec' => 'p.price', 'render' => 'renderPricePreferred', 'class' => 'alignRight text-right', 'label' => 'labelPricePreferred', 'vat' => 'Y', 'fieldType' => BaseList::TYPE_PRICE],
            'priceWithDiscount' => ['translate' => true, 'field' => 'priceWithDiscount', 'spec' => '(p.price - ((p.price * p.discount) / 100)) as priceWithDiscount', 'render' => 'renderPricePreferred', 'class' => 'alignRight text-right', 'label' => 'labelPricePreferredWithDiscount', 'vat' => 'Y', 'visible' => 'N'],
            'priceWithoutVat' => ['translate' => true, 'field' => 'p.price', 'spec' => 'p.price', 'render' => 'renderPrice', 'class' => 'alignRight text-right', 'visible' => 'N', 'vat' => 'N', 'fieldType' => BaseList::TYPE_PRICE],
            'Datum přidání' => ['field' => 'p.date_added', 'render' => 'renderDate'],
            'Skladem ks' => ['field' => 'p.in_store', 'spec' => 'p.in_store', 'visible' => 'N', 'render' => 'renderFloat'],
            'Varianty' => ['field' => 'variations', 'spec' => "GROUP_CONCAT(DISTINCT CONCAT(pv.title, ' - ', TRIM(pv.in_store)+0, ' ks') ORDER BY pv.id ASC) as variations", 'render' => 'renderVariations', 'export' => 'exportVariations', 'class' => 'text-wrap tiny-list-items', 'visible' => 'N'],
            'Pozice' => ['field' => 'p.position', 'spec' => 'p.position', 'visible' => 'N', 'render' => 'renderProductPosition'],
            'Ean' => ['field' => 'p.ean', 'visible' => 'N'],
            'shortDescription' => ['translate' => true, 'field' => 'p.short_descr', 'spec' => 'p.short_descr', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
            'longDescription' => ['translate' => true, 'field' => 'p.long_descr', 'spec' => 'p.long_descr', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
        ],
        'class' => 'getRowClass',
    ];

    public function getRowClass($values)
    {
        $class = '';
        if ($values['figure'] == 'O') {
            $class .= ' info';
        } elseif ($values['figure'] != 'Y') {
            $class .= ' danger';
        }
        if ($this->isImageVisible()) {
            $class .= ' product-list-thumbnail';
        }

        return $class;
    }

    public function renderProductPosition($values)
    {
        return match ($values['position']) {
            POSITION_FIRST => 'Vpředu',
            POSITION_LAST => 'Vzadu',
            null => 'Standartní řazení',
            default => $values['position'],
        };
    }

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

        $variations = explode(',', $variations ?: '');

        $ret = [];
        foreach ($variations as $variation) {
            $ret[] = HTML::create('span')
                ->tag('p')
                ->text($variation)
                ->end();
        }

        return $ret;
    }

    public function exportVariations($values, $column)
    {
        $array = explode(',', $this->getListRowValue($values, $column['field']));

        return $this->exportArray($array);
    }

    public function renderCampaign($values, $column)
    {
        $label = $this->getListRowValue($values, $column['field']);
        if (empty($label)) {
            return '';
        }
        global $cfg;
        $flags = preg_split('/,/', $label);

        $campaign_colors = ['N' => ' badge-pastel-primary',
            'A' => ' badge-pastel-danger',
            'V' => ' badge-pastel-warning',
            'S' => 'badge-pastel-default',
            'L' => 'badge-pastel-default',
            'M' => 'badge-pastel-default',
            'Z' => 'badge-pastel-default',
        ];
        $ret = [];
        foreach (array_intersect($flags, array_keys($cfg['Products']['Flags'])) as $flag) {
            $hidden = $cfg['Products']['Flags'][$flag]['hidden'] ?? false;
            if (!$hidden) {
                $short = $cfg['Products']['Flags'][$flag]['short'];
                $title = $cfg['Products']['Flags'][$flag]['singular'] != '' ? $cfg['Products']['Flags'][$flag]['singular'] : $short;
                $class = getVal($flag, $campaign_colors);
                $ret[] = HTML::create('span')
                    ->class('badge '.$class)
                    ->tag('span')->class('tooltip-text')->text($title)->end()
                    ->tag('span')->class('badge-text')->text($short)->end();
            }
        }

        return $ret;
    }

    public function renderLabels($values, $column)
    {
        $labels = $this->getListRowValue($values, 'label_values');
        if (empty($labels)) {
            return [];
        }

        $labels = json_decode($labels, true);
        $ret = [];
        foreach ($labels as $label) {
            $ret[] = HTML::create('span')
                ->class('badge')
                ->tag('span')->class('tooltip-text')->text($label['name'])->end()
                ->tag('span')->class('badge-text')->text($label['short_name'] ?: $label['name'])->end();
        }

        return $ret;
    }

    public function renderImage($values, $column)
    {
        $id = $this->getListRowValue($values, 'id');
        $SQL = sqlQueryBuilder()->select('ph.id', 'ph.source', 'ph.image_2', 'php.show_in_lead')
            ->from('photos', 'ph')
            ->leftJoin('ph', 'photos_products_relation', 'php', 'ph.id=php.id_photo')
            ->where(Operator::equals(['php.id_product' => $id, 'php.show_in_lead' => 'Y']))
        ->execute();
        foreach ($SQL as $row) {
            $img = getImage($row['id'], $row['image_2'], $row['source'], 4);
        }

        global $cfg;
        $ret = [];
        if (empty($img)) {
            $ret[] = \KupShop\KupShopBundle\Util\HtmlBuilder\HTML::create('img')
                ->class('img img-rounded')
                ->attr('src', '/admin/static/images/no-image.png');
        } else {
            $ret[] = \KupShop\KupShopBundle\Util\HtmlBuilder\HTML::create('img')
                ->class('img img-rounded')
                ->attr('src', $this->getUrlFinder()->staticUrl($img['source']));
        }

        return $ret;
    }

    public function labelPricePreferredWithDiscount(): string
    {
        switch (\Settings::getDefault()->prod_prefer_price_vat) {
            case 'Y':
                return 'Prodejní cena s DPH';

            case 'F':
                return 'Prodejní cena finální';

            default:
            case 'N':
                return 'Prodejní cena bez DPH';
        }
    }

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

        if (findModule(\Modules::POHODA)) {
            $tableDef['fields']['Datum posl. synch.'] = ['field' => 'p.pohoda_sync_date', 'render' => 'renderDateTime', 'visible' => 'Y'];
        }

        if (findModule(\Modules::PRODUCTS, \Modules::SUB_NOTE)) {
            $tableDef['fields']['Poznámka'] = [
                'field' => 'p.note',
                'spec' => 'COALESCE(GROUP_CONCAT(DISTINCT NULLIF(pv.note, "")), p.note) as note',
                'visible' => 'N',
            ];
        }

        $tableDef['fields']['Výrobce'] = [
            'field' => 'producer_name',
            'spec' => function (QueryBuilder $qb) {
                $qb->addSelect('pr.name as producer_name')
                    ->leftJoin('p', 'producers', 'pr', 'p.producer = pr.id');
            },
            'visible' => 'N',
        ];

        if (findModule(\Modules::WAREHOUSE)) {
            $tableDef['fields']['Pozice ve skladu'] = [
                'field' => 'warehouse_position',
                'size' => 2,
                'spec' => function (QueryBuilder $qb) {
                    $qb->addSelect('GROUP_CONCAT(DISTINCT wp.code SEPARATOR ", ") as warehouse_position')
                       ->leftJoin('p', 'warehouse_products', 'wpr', 'p.id = wpr.id_product AND (pv.id = wpr.id_variation OR wpr.id_variation is null)')
                       ->leftJoin('wpr', 'warehouse_positions', 'wp', 'wpr.id_position = wp.id');
                },
            ];
        }

        if (findModule(\Modules::STOCK_IN)) {
            $tableDef['fields']['stockInDate'] = [
                'field' => 'p.date_stock_in',
                'spec' => 'p.date_stock_in',
                'render' => 'renderDate',
                'visible' => 'N',
                'translate' => true,
            ];
        }

        if (findModule(\Modules::LABELS, \Modules::SUB_PRODUCT_LABELS)) {
            $tableDef['fields']['labels'] = [
                'field' => 'label_values',
                'render' => 'renderLabels',
                'class' => 'columnCampaigns',
                'translate' => true,
                'fieldType' => BaseList::TYPE_LIST_MULTISELECT_AUTOCOMPLETE,
                'fieldOptions' => ['autocomplete' => 'labels', 'table' => 'labels', 'fieldType' => 'json', 'prefetchField' => 'short_name'],
                'spec' => function (QueryBuilder $qb) {
                    $qb->addSubselect(
                        sqlQueryBuilder()
                            ->select('JSON_OBJECTAGG(l.id, JSON_OBJECT("short_name", l.short_name, "name", l.name, "id", l.id))')
                            ->from('product_labels_relation', 'plr')
                            ->leftJoin('plr', 'labels', 'l', 'plr.id_label = l.id')
                            ->andWhere('plr.id_product = p.id'), 'label_values'
                    );
                },
            ];
        }

        if (findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS)) {
            $tableDef['fields']['measure_unit'] = [
                'field' => 'measure_unit',
                'spec' => function (QueryBuilder $qb) {
                    $qb->addSelect('COALESCE(pu2.short_name_admin, pu2.short_name) unit_name, p.measure_unit')
                        ->leftJoin('p', 'products_units', 'pu2', 'p.measure_unit = pu2.id');
                },
                'translate' => true,
                'visible' => 'Y',
                'render' => 'renderMeasureUnit',
                'fieldType' => BaseList::TYPE_LIST_AUTOCOMPLETE,
                'fieldOptions' => [
                    'autocomplete' => 'units',
                    'prefetchField' => 'unit_name',
                ],
            ];

            $tableDef['fields']['measure_quantity'] = [
                'field' => 'p.measure_quantity',
                'spec' => 'p.measure_quantity',
                'visible' => 'Y',
                'translate' => true,
                'fieldType' => BaseList::TYPE_FLOAT,
            ];
        }

        global $cfg;

        foreach ($cfg['Products']['Flags'] as $flag => $value) {
            $tableDef['fields']['campaign']['fieldOptions'][$flag] = $value['singular'];
        }

        return $tableDef;
    }

    protected function isImageVisible()
    {
        return $this->getTableDef()['fields']['photo']['visible'] == 'Y';
    }

    public function getQuery()
    {
        $cfg = Config::get();
        $dbcfg = \Settings::getDefault();

        $qb = sqlQueryBuilder()
                    ->select('p.id', 'p.code', 'p.figure', 'p.date_added', 'p.discount', 'p.vat', 'p.ean')
                    ->from('products', 'p')
                    ->leftJoin('p', 'products_variations', 'pv', 'p.id=pv.id_product')
                    ->where('p.id != 0')
                    ->groupBy('p.id');

        $var['showImages'] = $this->isImageVisible();
        $var['url'] = $_SERVER['REQUEST_URI'];

        $filter = getVal('filter', null, []);
        if (!empty($filter)) {
            // extended search
            ServiceContainer::getService(ProductListFilter::class)->applyFilter($filter, $qb);

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

        extract($_GET, EXTR_SKIP | EXTR_REFS);

        $IDsec = getVal('IDsec');
        $comments = getVal('comments');
        $adminID = getVal('adminID');

        if (!empty($_GET['IDsec']) && empty($campaign)) {
            $qb->leftJoin('p', 'products_in_sections', 'ps', 'p.id=ps.id_product')
                ->andWhere('ps.id_section=:id_section')
                ->setParameter('id_section', $_GET['IDsec']);
        }

        // ###########
        if (isset($_GET['nosec'])) {
            $qb->resetQueryPart('from');
            $qb->from('products', 'p')
                ->leftJoin('p', 'products_in_sections', 'ps', 'p.id = ps.id_product')
                ->andWhere('ps.id_product IS NULL');
        }

        // ###########
        if (isset($_GET['noimage'])) {
            $qb->resetQueryPart('from');
            $qb->from('products', 'p')
                ->leftJoin('p', 'photos_products_relation', 'ppr', 'p.id = ppr.id_product AND ppr.show_in_lead="Y"')
                ->andWhere('ppr.id_product IS NULL');
        }

        if (isset($_GET['in_store'])) {
            $qb->andWhere('p.in_store > 0');
        }

        // ###########
        if (!empty($IDp)) {
            $IDp = trim($IDp);
            $qb->andWhere('p.id=:pid')
                ->setParameter('pid', $IDp);
        }

        // ###########
        if (!empty($IDvv)) {
            $IDvv = trim($IDvv);
            $qb->join('pv', 'products_variations_combination', 'pvcv', 'pv.id=pvcv.id_variation')
                ->andWhere('pvcv.id_value=:idvv')
                ->setParameter('idvv', $IDvv);
        }

        // ###########
        if (!empty($idCode)) {
            $searchFields = $this->getCodeSearchFields($qb);

            if (!empty($cfg['Modules']['products_variations']['variationCode'])) {
                $searchFields = array_merge($searchFields, [['field' => 'pv.code', 'match' => 'both', 'order' => '1']]);
            }

            if (findModule(\Modules::PRODUCTS_SUPPLIERS)) {
                $qb->leftJoin('p', 'products_of_suppliers', 'pofs', 'p.id = pofs.id_product');
                $searchFields = array_merge($searchFields, [['field' => 'pofs.code', 'match' => 'both', 'order' => '1']]);
            }

            $qb->andWhere(Search::searchFields($idCode, $searchFields));
        }

        // ###########
        if (!empty($code)) {
            $code = trim($code);
            $qb->andWhere('p.code LIKE :code')
                ->setParameter('code', '%'.$code.'%');
            if (!empty($cfg['Modules']['products_variations']['variationCode'])) {
                $qb->orWhere('pv.code LIKE :code');
            }

            if (findModule(\Modules::PRODUCTS_SUPPLIERS)) {
                $qb->leftJoin('p', 'products_of_suppliers', 'pofs', 'p.id = pofs.id_product')
                    ->orWhere('pofs.code LIKE :pofs_code')
                    ->setParameter('pofs_code', $code);
            }
        }

        // ###########
        if (!empty($title)) {
            $this->addFilterForTitle($title, $qb);
        }

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

        // ###########
        $IDpr = getVal('IDpr');
        if (!empty($IDpr)) {
            $IDpr = trim($IDpr);
            $qb->andWhere('p.producer=:id_producer')
                ->setParameter('id_producer', $IDpr);
        }

        // ###########
        if (!empty($campaign)) {
            $qb->andWhere('FIND_IN_SET(:campaign, p.campaign)>0')
                ->setParameter('campaign', $campaign);

            if (!empty($_GET['IDsec'])) {
                $qb->join('p', 'products_in_sections', 'ps',
                    'p.id=ps.id_product AND FIND_IN_SET(:campaign2, p.campaign)>0 AND ps.id_section=:ps_id_section'
                )
                    ->setParameter('campaign2', $campaign)
                    ->setParameter('ps_id_section', $_GET['IDsec']);
            }
        }

        // ###########
        if (!empty($figure)) {
            $qb->andWhere('p.figure=:figure')
                ->setParameter('figure', $figure);
        }

        // ###########
        // zobrazeni zbozi s novymu komentari
        if ($comments == 'new' && $adminID > 0) {
            $qb2 = sqlQueryBuilder()
                        ->select('date_access')
                        ->from('admins_accesses')
                        ->where('id_admin=:id_admin AND login_status="OK"')
                        ->setParameter('id_admin', intval($adminID))
                        ->orderBy('id', 'DESC')
                        ->setMaxResults(1)
                        ->setFirstResult(1);
            $dateLogin = $qb2->execute()->fetch()['date_access'];

            if (empty($dateLogin)) {
                $dateLogin = date('Y-m-d').' 00:00:00';
            }

            $qb->join('p', 'comments', 'c')
                ->where('c.type="product" AND c.id_item=p.id AND c.date >= :comment_date')
                ->setParameter('comment_date', $dateLogin);
        }

        // ###########
        if (!empty($show_in_feed)) {
            $qb->andWhere('p.show_in_feed=:show_in_feed')
                ->setParameter('show_in_feed', $show_in_feed);
        }

        // ###########
        if (!empty($parameter_value)) {
            $qb->leftJoin('p', 'parameters_products', 'pp', 'pp.id_product = p.id')
                ->andWhere('pp.value_list=:id_pp_value')
                ->setParameter('id_pp_value', $parameter_value);
        }

        if (!empty($template_id)) {
            $qb->leftJoin('p', 'templates_products', 'tp', 'tp.id_product = p.id')
                ->andWhere(\Query\Operator::equals(['tp.id_template' => $template_id]));
        }

        // ###########
        if (!getVal('showOld')) {
            $qb->andWhere('p.figure != "O" ');
        }

        if (($parameterID = getVal('parameterId')) && ($parameterValue = getVal('parameterValue'))) {
            $qb->leftJoin('p', 'parameters_products', 'pp', 'pp.id_parameter = :id_parameter AND pp.id_product = p.id')
                ->leftJoin('pp', 'parameters_list', 'pl', 'pl.id = pp.value_list')
                ->andWhere('(pp.value_char LIKE :parameter_value) OR (pp.value_float LIKE :parameter_value) OR (pl.value LIKE :parameter_value)')
                ->addParameters(['id_parameter' => $parameterID, 'parameter_value' => $parameterValue.'%']);
        }

        if (findModule(\Modules::POHODA)) {
            $qb->addSelect('p.pohoda_sync_date');
        }

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

    protected function getCodeSearchFields(QueryBuilder $qb): array
    {
        return [
            ['field' => 'p.code', 'match' => 'both', 'order' => '1'],
            ['field' => 'p.id', 'match' => 'both', 'order' => '1'],
        ];
    }

    protected function addFilterForTitle($title, $qb): void
    {
        $search = get_search_query($title, [['field' => 'p.title', 'match' => 'both']]);
        $qb->andWhere($search['where']);

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

    public function renderMeasureUnit($values, $column)
    {
        return $values['unit_name'] ?? '';
    }
}

return ProductsList::class;
