<?php

namespace intec\template\actions;

use intec\core\base\InvalidConfigException;
use intec\core\helpers\ArrayHelper;
use intec\core\helpers\Type;
use intec\core\platform\iblock\ElementArrayConverter;
use intec\core\platform\iblock\Elements;
use intec\core\platform\iblock\ElementsQuery;
use intec\template\catalog\Compare;
use intec\template\Template;

/**
 * Класс, представляющий контроллер-обработчик действий корзины
 * @author Intec
 * @version 1.0.0
 * @package intec\template\actions
 */
class CompareActions extends BaseActions
{
    /**
     * Список сравнения
     * @var \intec\template\catalog\Compare
     */
    protected $_compare;

    /**
     * Компонент списка сравнения
     * @var \intec\template\catalog\CompareComponent
     */
    protected $_compareComponent;

    /**
     * Форматтер элементов списка сравнения
     * @var \intec\template\catalog\BaseCompareItemsFormatter
     */
    protected $_formatter;

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();

        try {
            $this->_compareComponent = Template::getInstance()->getCompare();
            $this->_compare = $this->_compareComponent->getCompare();
            $this->_formatter = $this->_compareComponent->getFormatter();
        } catch (InvalidConfigException) {
            die('Initialization error');
        }
    }

    /**
     * Действие добавления элемента в список сравнения
     * @param array $data Данные добавляемого элемента
     * @return array
     */
    public function actionAdd($data)
    {
        $item = \CIBlockElement::GetByID($data['id'])->Fetch();

        if (empty($item))
            return $this->errorResponse('notExists', 'Element does not exists');

        if ($this->getCompare() instanceof Compare)
            $item = $this->getCompare()->processItem($item);

        $item = (new ElementArrayConverter())->convert($item);
        $isSuccess = $this->getCompare()->add(
            $item->getId(),
            $item->getIblockId(),
            $data['code']
        );

        if ($isSuccess) {
            $iblockId = $item->getIblockId();
            $item = $this->getFormatter()->format(new Elements([$item]));
            reset($item);
            $item[0]['iblockId'] = $iblockId;
            return $this->successResponse($item[0]);
        }

        return $this->errorResponse('notAdded', 'Unable to add element');
    }

    /**
     * Действие очистки списка сравнения
     * @param string $code Код сравнения
     * @return array
     */
    public function actionClear($code)
    {
        if (!$this->getCompare()->clear($code))
            return $this->errorResponse('notCleared', 'Unable to clear compare');

        return $this->successResponse($this->getFormattedItems($code));
    }

    /**
     * Действие удаления элемента из списка сравнения
     * @param array $data Данные удаляемого элемента
     * @return array
     */
    public function actionDelete($data)
    {
        $item = \CIBlockElement::GetByID($data['id'])->Fetch();

        if (empty($item))
            $this->errorResponse('notExists', 'Element does not exists');

        if ($this->getCompare() instanceof Compare)
            $item = $this->getCompare()->processItem($item);

        $item = (new ElementArrayConverter())->convert($item);
        $isSuccess = $this->getCompare()->delete(
            $item->getId(),
            $item->getIblockId(),
            $data['code']
        );

        if ($isSuccess) {
            $item = $this->getFormatter()->format(new Elements([$item]));
            reset($item);

            return $this->successResponse($item[0]);
        }

        return $this->errorResponse('notDeleted', 'Unable to delete element');
    }

    /**
     * Действие получения данных списка сравнения
     * @param string $code Код сравнения
     * @return array
     */
    public function actionGetData($code)
    {
        if (empty($code))
            return $this->errorResponse('badRequest', 'Bad compare code');

        $result = [
            'count' => 0,
            'code' => $code,
            'iblocks' => $this->getFormattedData($code)
        ];

        if (!empty($result['iblocks'])) {
            foreach ($result['iblocks'] as $iblock) {
                $result['count'] += $iblock['count'];
            }
        }

        return $this->successResponse($result);
    }

    /**
     * Действие получения элеменов списка сравнения
     * @param string $code Код сравнения
     * @return array
     */
    public function actionGetItems($code)
    {
        return $this->successResponse($this->getFormattedItems($code));
    }

    /**
     * @inheritdoc
     */
    public function beforeAction($action, $parameters)
    {
        if (parent::beforeAction($action, $parameters))
            return $this->getCompareComponent()->enabled;

        return false;
    }

    /**
     * @inheritdoc
     */
    public function bindActionParameters($action, $parameters)
    {
        if ($action->getId() === 'add' || $action->getId() === 'delete')
            return [
                'data' => $parameters
            ];

        return parent::bindActionParameters($action, $parameters);
    }

    /**
     * Возвращает форматированные данные списка сравнения
     * @param string $code Код сравнения
     * @return array
     */
    public function getFormattedData($code)
    {
        $items = $this->getFormattedItems($code);
        $iblocks = $this->getFormattedIBlocks($code);

        foreach ($iblocks as &$iblock) {
            foreach ($iblock['items'] as &$itemId) {
                foreach ($items as &$item) {
                    if ($item['id'] === $itemId)
                        $itemId = $item;
                }
            }
        }

        return $iblocks;
    }

    /**
     * Возвращает инфоблоки сравнения
     * @param string $code Код сравнения
     * @return array
     */
    public function getFormattedIBlocks($code)
    {
        $result = [];
        $iblocks = [];
        $data = $this->getCompare()->getIBlocks($code);

        foreach ($data as $iblock => $items)
            $iblocks[] = $iblock;

        if (empty($iblocks))
            return $result;

        $iblocks = \CIBlock::GetList([], [
            'ID' => $iblocks
        ]);

        while ($iblock = $iblocks->GetNext(true, false))
            $result[] = [
                'id' => Type::toInteger($iblock['ID']),
                'code' => $iblock['CODE'],
                'name' => $iblock['NAME'],
                'count' => 0,
                'items' => []
            ];

        unset($iblocks, $iblock);

        foreach ($result as &$iblock) {
            if (ArrayHelper::keyExists($iblock['id'], $data)) {
                $iblock['count'] = count($data[$iblock['id']]);
                $iblock['items'] = $data[$iblock['id']];
            }
        }

        return $result;
    }

    /**
     * Возвращает элементы списка сравнения
     * @param string $code Код списка сравнения
     * @return array
     */
    public function getFormattedItems($code)
    {
        $result = [];
        $id = $this->getCompare()->getList($code);

        if (!empty($id)) {
            $items = (new ElementsQuery())
                ->setUseTilda(false)
                ->setWithProperties(false)
                ->setElementsId($id)
                ->execute();

            if (!$items->isEmpty())
                $result = $this->getFormatter()->format($items);
        }

        return $result;
    }

    /**
     * Возвращает инстанс списка сравнения
     * @return \intec\template\catalog\Compare
     */
    public function getCompare()
    {
        return $this->_compare;
    }

    /**
     * Возвращает инстанс компонента сравнения
     * @return \intec\template\catalog\CompareComponent
     */
    public function getCompareComponent()
    {
        return $this->_compareComponent;
    }

    /**
     * Возвращает форматтер элементов списка сравнения
     * @return \intec\template\catalog\BaseCompareItemsFormatter
     */
    public function getFormatter()
    {
        return $this->_formatter;
    }
}
