<?php

namespace KupShop\ReclamationsBundle\View;

use KupShop\KupShopBundle\Exception\RedirectException;
use KupShop\KupShopBundle\Query\JsonOperator;
use KupShop\KupShopBundle\Util\Database\QueryHint;
use KupShop\KupShopBundle\Views\View;
use KupShop\ReclamationsBundle\Query\Reclamations;
use KupShop\ReclamationsBundle\Util\ReclamationsUtil;
use Query\Filter;
use Query\Operator;
use Query\Product;

class CreateReclamationView extends View
{
    protected static $type = 'reclamations';

    protected $template = 'reclamations/reclamations-new.products.tpl';
    protected string $smartyFallback = 'account';
    protected string $entrypoint = 'account';

    private string $step = 'login';

    protected array $steps;

    private $itemId;
    private $itemPieces;

    protected $reclamationsUtil;

    private \Pager $pager;
    private array $filter;

    public function __construct(ReclamationsUtil $reclamationsUtil)
    {
        $this->reclamationsUtil = $reclamationsUtil;

        $this->steps = $this->getSteps();
        $this->setPager(new \Pager());
    }

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

        $vars['steps'] = $this->steps;
        $vars['stepName'] = $this->getStep();
        $page = getVal('page', null, 1);
        $noOnPage = 50;
        $pager = $this->getPager();
        $pager->setOnPage($noOnPage);
        $pager->setPageNumber($page);

        $items = $this->getBoughtItems();
        $vars['filter'] = $this->filter ?? [];

        if ($this->getStep() == 'products') {
            $productList = new \ProductList();
            $productList->setVariationsAsResult(true);

            $products = [];

            $vars['items'] = $items;

            foreach ($vars['items'] as $item) {
                $products[$item['id_product']] = $products[$item['id_product']] ?? null;

                if ($item['id_variation']) {
                    $products[$item['id_product']][] = $item['id_variation'];
                }
            }

            $productList->andSpec(Product::productsAndVariationsIds($products));
            $productList->fetchImages('product_gallery', null, true);

            $products = $productList->getProducts();

            $vars['itemsInOrder'] = [];

            foreach ($vars['items'] as &$item) {
                $key = $item['id_product'];

                if ($item['id_variation']) {
                    $key .= '/'.$item['id_variation'];
                }

                $item['product'] = $products[$key];

                if (empty($vars['itemsInOrder'][$item['id_order']][$item['id']])) {
                    $vars['itemsInOrder'][$item['id_order']][$item['id']] = $item;
                }
            }
        }

        if ($this->step == 'summary' && $this->itemId) {
            $itemExists = false;
            foreach ($items as $item) {
                if ($item['id'] == $this->itemId && !$item['expired']) {
                    $itemExists = true;
                    $selected = $item;
                    break;
                }
            }

            if (!$itemExists) {
                $this->addErrorMessage(translate('error_item', 'reclamations'));
                throw new RedirectException(path('kupshop_reclamations_reclamations_createreclamation'));
            }

            if (!empty($selected['id_variation'])) {
                $product = new \Variation($selected['id_product'], $selected['id_variation']);
            } else {
                $product = new \Product($selected['id_product']);
            }

            $product->createFromDB();
            $product->fetchImages('product_gallery');

            $vars['item'] = $selected;
            $vars['item']['product'] = $product;
            $vars['item']['pieces_to_return'] = $this->itemPieces;

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

        $vars['preferred_handle_types'] = $this->reclamationsUtil->getPrefHandleTypes();
        $vars['pager'] = $pager;

        return $vars;
    }

    public function getOrder(): ?\Order
    {
        $orderId = sqlQueryBuilder()
            ->select('id_order')
            ->from('order_items')
            ->where(Operator::equals(['id' => $this->itemId]))
            ->execute()->fetchColumn();

        if ($orderId) {
            $order = new \Order();
            $order->createFromDB($orderId);

            return $order;
        }

        return null;
    }

    public function handleStep_reclamationSummary($delivery, $bankAccount, $preferred_handle_type, $note, $user_content)
    {
        $order = $this->getOrder();
        // validate required address fields
        foreach ($this->reclamationsUtil->getAddressFields($order->getDeliveryType()->requiresDeliveryAddress()) as $field) {
            if (empty($delivery[$field])) {
                addUserMessage(translate('error_delivery_fields', 'reclamations'), 'danger');
                throw new RedirectException(path('kupshop_reclamations_reclamations_createreclamationsummary',
                    ['id_item' => $this->itemId]));
            }
        }

        if (empty($note)) {
            addUserMessage(translate('error_note', 'reclamations'), 'danger');
            throw new RedirectException(path('kupshop_reclamations_reclamations_createreclamationsummary', ['id_item' => $this->itemId]));
        }

        if ($id = QueryHint::withRouteToMaster(function () use ($delivery, $bankAccount, $preferred_handle_type, $note, $user_content) {
            return $this->reclamationsUtil->createReclamation($this->itemId, $this->itemPieces, $delivery, $bankAccount, $preferred_handle_type, $note, true, $user_content);
        })) {
            throw new RedirectException(path('kupshop_reclamations_reclamations_reclamation', ['id' => $id, 'success' => 1]));
        }
    }

    protected function getBoughtItems()
    {
        $products = sqlQueryBuilder()
            ->select('oi.*, COALESCE(o.date_delivered, o.date_handle, o.date_created) as delivery_date, p.guarantee, o.order_no')
            ->from('order_items', 'oi')
            ->leftJoin('oi', 'orders', 'o', 'o.id = oi.id_order')
            ->leftJoin('oi', 'products', 'p', 'p.id = oi.id_product')
            ->addSelect(Reclamations::getReturnablePiecesSpec())
            ->andWhere('oi.id_product IS NOT NULL')
            ->andWhere('oi.pieces > 0')
            ->andWhere(Operator::inIntArray(getStatuses('handled'), 'o.status'))
            ->andWhere(
                Operator::orX(
                    Operator::not(JsonOperator::contains('oi.note', 'item_type', 'gift')),
                    Operator::equalsNullable(['JSON_CONTAINS(oi.note,\'"gift"\',\'$.item_type\')' => null])
                )
            )
            ->andWhere('o.status_storno != 1')
            ->andWhere($this->reclamationsUtil->getOrdersSpec())
            ->orderBy('delivery_date', 'DESC')
            ->groupBy('oi.id');

        if (findModule(\Modules::CURRENCIES)) {
            $products->addSelect('o.currency');
        }

        $products
            ->addSelect($this->reclamationsUtil->getExpiredItemsSpec())
            ->addCalcRows();

        if ($this->getStep() == 'products') {
            $products->andWhere($this->getPager()->getSpec());
        }

        // Filter:
        // Vyhledat produkt
        if (!empty($this->filter['product'])) {
            $products->andWhere(Filter::search($this->filter['product']));
        }
        // Vyhledat objednávku
        if (!empty($this->filter['order'])) {
            $order = sqlQueryBuilder()->select('id, order_no')->from('orders')
                ->andWhere(Operator::equals(['id' => $this->filter['order'], 'order_no' => $this->filter['order']], 'OR'))
                ->execute()->fetchAssociative();
            if ($order) {
                $products->andWhere(Operator::equals(['o.id' => $order['id']]));
            }
            $this->filter['order'] = ($order ? $order['order_no'] : null);
        }

        $return = [];
        $productsList = $products->execute();
        $this->getPager()->setTotal(returnSQLResult('SELECT FOUND_ROWS()'));
        foreach ($productsList as $item) {
            $piecePrice = toDecimal($item['piece_price']);
            $piecePrice = $piecePrice->addVat($item['tax']);

            $item['piece_price_with_vat'] = $piecePrice;

            $return[] = $item;
        }

        return $return;
    }

    public function getBreadcrumbs()
    {
        return getReturnNavigation(-1, 'RECLAMATION', [$this->getTitle()]);
    }

    public function getTitle()
    {
        return $this->getActiveStep()['descr'];
    }

    public function setItemId($itemId)
    {
        $this->itemId = $itemId;

        return $this;
    }

    public function setItemPieces($itemPieces)
    {
        $this->itemPieces = $itemPieces;

        return $this;
    }

    public function setStep($step)
    {
        $this->step = $step;

        return $this;
    }

    public function getTemplate(): string
    {
        switch ($this->step) {
            case 'login':
                return 'reclamations/reclamations-new.login.tpl';
            case 'products':
                return 'reclamations/reclamations-new.products.tpl';
            case 'summary':
                return 'reclamations/reclamations-new.summary.tpl';
        }

        return parent::getTemplate();
    }

    private function getSteps(): array
    {
        return [
            'login' => [
                'title' => translate('step_login', 'reclamations'),
                'descr' => translate('step_login_descr', 'reclamations'),
            ],
            'products' => [
                'title' => translate('step_products', 'reclamations'),
                'descr' => translate('step_products_descr', 'reclamations'),
            ],
            'summary' => [
                'title' => translate('step_summary', 'reclamations'),
                'descr' => translate('step_summary_descr', 'reclamations'),
            ],
            'success' => [
                'title' => translate('step_success', 'reclamations'),
            ],
        ];
    }

    public function getStep(): string
    {
        return $this->step;
    }

    private function getActiveStep(): array
    {
        return $this->steps[$this->getStep()];
    }

    private function getPager(): \Pager
    {
        return $this->pager;
    }

    private function setPager(\Pager $pager): void
    {
        $this->pager = $pager;
    }

    public function setFilter(array $filter): void
    {
        $this->filter = $filter;
    }
}
