<?php
/**
 * @author  Magediary
 * @package Magediary_ProductQuestion
 */

namespace Magediary\ProductQuestion\Ui\Component\Listing;

use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Store\Model\Store;
use Magento\Eav\Model\Config;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\DB\Select;

class AnswerDataProvider extends SearchResult
{
    /**
     * @var ProductMetadataInterface
     */
    private $productMetadata;

    /**
     * Add filter
     *
     * @inheirtDoc
     */
    protected function _construct()
    {
        parent::_construct();
        $this->addFilterToMap(
            'answer_id',
            'main_table.answer_id'
        );
        $this->addFilterToMap(
            'detail',
            'main_table.detail'
        );
        $this->addFilterToMap(
            'status',
            'main_table.status'
        );
        $this->addFilterToMap(
            'created_at',
            'main_table.created_at'
        );
        $this->addFilterToMap(
            'updated_at',
            'main_table.updated_at'
        );
    }

    /**
     * Get object
     *
     * @return ProductMetadataInterface|mixed
     */
    private function getProductMetadata()
    {
        if ($this->productMetadata == null) {
            $this->productMetadata = ObjectManager::getInstance()->get(ProductMetadataInterface::class);
        }
        return $this->productMetadata;
    }

    /**
     * @inheritdoc
     *
     * @return $this|AnswerDataProvider|void
     * @throws LocalizedException
     */
    protected function _initSelect()
    {
        parent::_initSelect();

        $tableQuestion = $this->getResource()->getTable('magediary_question');
        $tableQuestionProduct = $this->getResource()->getTable('magediary_question_product');
        $tableProductVarchar = $this->getResource()->getTable('catalog_product_entity_varchar');
        $tableProductEntity = $this->getResource()->getTable('catalog_product_entity');
        $storeId = Store::DEFAULT_STORE_ID;

        $this->getSelect()
            ->joinLeft(
                ['e' => $tableQuestionProduct],
                'e.question_id = main_table.question_id',
                ['product_id']
            )
            ->joinLeft(
                ['q' => $tableQuestion],
                'q.question_id = main_table.question_id',
                ['question_detail' => 'q.detail', 'question_id' => 'q.question_id']
            )
            ->group('main_table.answer_id');
        ;

        $productNameAttributeId = ObjectManager::getInstance()->get(Config::class)
            ->getAttribute(Product::ENTITY, ProductInterface::NAME)
            ->getAttributeId();

        if (in_array($this->getProductMetadata()->getEdition(), ['Enterprise', 'B2B'])) {
            $this->addExpressionFieldToSelect(
                'name',
                '(SELECT GROUP_CONCAT(\' \', n.value)
                    FROM ' . $tableProductVarchar . ' n
                    WHERE n.attribute_id = ' . $productNameAttributeId . ' AND {{entity_id}} IN
                        (SELECT row_id FROM ' . $tableProductEntity . ' nc
                            INNER JOIN (SELECT MIN(row_id) min_row_id FROM ' . $tableProductEntity .
                            ' GROUP BY entity_id) nb ON nc.row_id = nb.min_row_id
                            WHERE nc.entity_id IN
                                (SELECT product_id
                                FROM ' . $tableQuestionProduct . ' na
                                WHERE na.product_id = nc.entity_id AND main_table.question_id = na.question_id
                                )
                        ) AND store_id = ' . $storeId . '
                    )',
                ['entity_id' => 'n.row_id']
            );

            $this->addExpressionFieldToSelect(
                'sku',
                '(SELECT GROUP_CONCAT(\' \', s.sku)
                    FROM ' . $tableProductEntity . ' s
                    WHERE {{entity_id}} IN
                        (SELECT row_id FROM ' . $tableProductEntity . ' sc
                            INNER JOIN (SELECT MIN(row_id) min_row_id FROM ' . $tableProductEntity .
                            ' GROUP BY entity_id) sb ON sc.row_id = sb.min_row_id
                            WHERE sc.entity_id IN
                                (SELECT product_id
                                FROM ' . $tableQuestionProduct . ' sa
                                WHERE sa.product_id = sc.entity_id AND main_table.question_id = sa.question_id
                                )
                        )
                    )',
                ['entity_id' => 's.row_id']
            );
        } else {
            $this->addExpressionFieldToSelect(
                'name',
                '(SELECT GROUP_CONCAT(\' \', product_varchar.value)
                    FROM ' . $tableProductVarchar . ' product_varchar
                    WHERE product_varchar.attribute_id = ' . $productNameAttributeId .' AND {{entity_id}} IN
                        (SELECT entity_id FROM ' . $tableQuestionProduct . ' z
                        WHERE {{entity_id}} = z.product_id AND main_table.question_id = z.question_id
                        ) AND store_id = ' . $storeId . '
                    )',
                ['entity_id' => 'product_varchar.entity_id']
            );

            $this->addExpressionFieldToSelect(
                'sku',
                '(SELECT GROUP_CONCAT(\' \', s.sku)
                    FROM ' . $tableProductEntity . ' s
                    WHERE {{entity_id}} IN (SELECT entity_id
                        FROM ' . $tableQuestionProduct . ' z
                        WHERE {{entity_id}} = z.product_id AND main_table.question_id = z.question_id
                        )
                    )',
                ['entity_id' => 's.entity_id']
            );
        }

        return $this;
    }

    /**
     * Get total records
     *
     * @return int
     */
    public function getSize()
    {
        if ($this->_totalRecords === null) {
            $sql = $this->getSelect();
            $sql->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
            $this->_totalRecords = count($this->getConnection()->fetchAll($sql, $this->_bindParams));
        }
        return (int) $this->_totalRecords;
    }

    /**
     * Add custom filter conditions
     *
     * @param array|string $field
     * @param mixed $condition
     * @return $this|SearchResult
     */
    public function addFieldToFilter($field, $condition = null)
    {
        if (is_array($field)) {
            $conditions = [];
            foreach ($field as $key => $value) {
                $conditions[] = $this->_translateCondition($value, isset($condition[$key]) ? $condition[$key] : null);
            }
            $resultCondition = '(' . implode(') ' . Select::SQL_OR . ' (', $conditions) . ')';
        } else {
            $resultCondition = $this->_translateCondition($field, $condition);
        }

        if ($field=='sku' || $field=='name' || $field=='question_detail') {
            $this->_select->having($resultCondition, null, Select::TYPE_CONDITION);
        } else {
            $this->_select->where($resultCondition, null, Select::TYPE_CONDITION);
        }

        return $this;
    }
}
