<?php

namespace KupShop\PohodaBundle\Utils\Tools;

use KupShop\AdminBundle\Util\ActivityLog;
use KupShop\BonusProgramBundle\Utils\BonusComputer;
use KupShop\OrderingBundle\Util\Order\OrderImporter;
use KupShop\PohodaBundle\Utils\PohodaBase;
use Query\Operator;

class PohodaOrderImporter extends OrderImporter
{
    use PohodaBase;
    protected $searchProductAndVariationByEan = false;
    /**
     * @var BonusComputer
     */
    protected $bonusComputer;

    public function importOrder($orderElement, $edit, $insert)
    {
        try {
            $this->addResponseLog('Order Import', $orderElement->asXML());
            parent::importOrder($orderElement, $edit, $insert);
        } catch (\Exception $e) {
            if (intval($e->getPrevious()->errorInfo[1]) === 1451) {
                addActivityLog(ActivityLog::SEVERITY_ERROR, ActivityLog::TYPE_SYNC, 'Nepodařilo se aktualizovat objednávku.', ['error' => $e->getMessage()]);
            } else {
                throw $e;
            }
        }
    }

    protected function searchOrder($order)
    {
        $qbOrder = sqlQueryBuilder()
            ->select('id')
            ->from('orders')
            ->andWhere(
                Operator::orX(
                    Operator::equals(['pohoda_id' => (string) $order->ORDER_POHODA_ID]),
                    Operator::equals(['pohoda_id' => $this->pohodaConnector->getMServerPrefix().((string) $order->ORDER_POHODA_ID)]),
                )
            )
            ->execute()
            ->fetchOne();

        if (empty($qbOrder)) {
            $qbOrder = sqlQueryBuilder()
                ->select('id')
                ->from('orders')
                ->andWhere('order_no=:code')
                ->setParameter('code', str_replace('web', '', (string) $order->ORDER_NO))
                ->execute()
                ->fetchOne();

            if ($qbOrder) {
                $order_data['pohoda_id'] = $this->pohodaConnector->getMServerPrefix().((string) $order->ORDER_POHODA_ID);
            }
        }

        $package_id = (string) $order->PACKAGE_ID;
        if ($package_id) {
            $qbOrder2 = sqlQueryBuilder()
                ->select('package_id')
                ->from('orders')
                ->andWhere('order_no=:code')
                ->setParameter('code', str_replace('web', '', (string) $order->ORDER_NO))
                ->execute()
                ->fetchOne();
            if (empty($qbOrder2)) {
                $order_data['package_id'] = $package_id;
            }
        }
        if (!empty($order_data) && $qbOrder) {
            sqlQueryBuilder()->update('orders')
                 ->directValues($order_data)
                 ->where(Operator::equals(['id' => $qbOrder]))
                 ->execute();
        }

        // Nechci aktualizovat objednávky, pokud to nemám povolený v configu.
        // Sem jsem se dostal kvůli dopárování pohoda_id při chybě v OrdersExporter
        if (!findModule(\Modules::POHODA, \Modules::SUB_ORDERS_IMPORT)) {
            return null;
        }

        return $qbOrder;
    }

    public function resolveOrder($orderElement, $qbOrder)
    {
    }

    protected function searchUser($order)
    {
        if (empty((string) $order->USER->POHODA_ID) || !findModule(\Modules::POHODA, \Modules::SUB_USERS)) {
            return false;
        }

        return sqlQueryBuilder()
            ->select('id')
            ->from('users')
            ->andWhere('pohoda_id=:userId')
            ->setParameter('userId', (string) $order->USER->POHODA_ID)
            ->execute()
            ->fetchColumn();
    }

    protected function getVariationAndProductIds($item)
    {
        $searchValue = ($this->searchProductAndVariationByEan ?? false) ? (string) $item->EAN : (string) $item->CODE;

        if (findModule(\Modules::PRODUCTS_VARIATIONS)) {
            $qbVariation = $this->getProductVariationByCode($searchValue);
            if ($qbVariation) {
                return $qbVariation;
            }
        }

        $qbProduct = $this->getProductByCode($searchValue);
        if ($qbProduct) {
            $qbProduct['id_variation'] = null;
            $qbProduct['title_variation'] = null;

            return $qbProduct;
        }

        return null;
    }

    protected function getProductVariationByCode($code)
    {
        $qb = sqlQueryBuilder()
            ->select('pv.id as id_variation, pv.id_product as id_product, pv.title as title_variation, p.title as title_product')
            ->from('products_variations', 'pv')
            ->leftJoin('pv', 'products', 'p', 'p.id=pv.id_product');

        if ($this->searchProductAndVariationByEan) {
            $qb->andWhere('pv.ean=:product_ean')->setParameter('product_ean', $code);
        } else {
            $qb->andWhere('pv.code=:product_code')->setParameter('product_code', $code);
        }

        return $qb->execute()->fetch();
    }

    protected function getProductByCode($code)
    {
        $qb = sqlQueryBuilder()
            ->select('id as id_product, title as title_product')
            ->from('products');

        if ($this->searchProductAndVariationByEan) {
            $qb->andWhere('ean=:product_ean')->setParameter('product_ean', $code);
        } else {
            $qb->andWhere('code=:product_code')->setParameter('product_code', $code);
        }

        return $qb->execute()->fetch();
    }

    protected function searchDelivery($order)
    {
        $delData = sqlFetch(
            sqlQuery(
                '
                SELECT dt.id as id, dtp.name as payment_name, dtd.name as delivery_name 
                    FROM delivery_type dt
                    LEFT JOIN delivery_type_delivery dtd ON dt.id_delivery = dtd.id
                    LEFT JOIN delivery_type_payment dtp on dt.id_payment = dtp.id
                    WHERE dtd.class=:type_del AND dtp.class=:type_pay ',
                [
                    'type_del' => (string) $order->DELIVERY,
                    'type_pay' => (string) $order->PAYMENT,
                ]
            )
        );

        if (!$delData) {
            $delData = $this->searchDeliveryByName($order);
        }

        return [$delData['delivery_name'] ?? null, $delData['id'] ?? null, $delData['payment_name'] ?? null];
    }

    private function searchDeliveryByName($order)
    {
        return sqlQueryBuilder()
            ->select('dt.id as id, dtp.name as payment_name, dtd.name as delivery_name')
            ->from('delivery_type', 'dt')
            ->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dt.id_delivery = dtd.id')
            ->leftJoin('dt', 'delivery_type_payment', 'dtp', 'dt.id_payment = dtp.id')
            ->where(
                Operator::andX(
                    Operator::equals(['JSON_UNQUOTE(JSON_EXTRACT(dtd.data, "$.pohoda_delivery"))' => (string) $order->DELIVERY_NAME]),
                    Operator::equals(['JSON_UNQUOTE(JSON_EXTRACT(dtp.data, "$.pohoda_payment"))' => (string) $order->PAYMENT_NAME])
                )
            )
            ->execute()
            ->fetchAssociative();
    }

    protected function addOrderAdditionalFields(&$orderRow, $orderElement)
    {
        $orderRow['pohoda_sync_date'] = (new \DateTime())->format('Y-m-d H:i:s');
        $orderRow['pohoda_id'] = $this->pohodaConnector->getMServerPrefix().((string) $orderElement->ORDER_POHODA_ID);

        if (!empty((string) $orderElement->FLAGS)) {
            $orderRow['flags'] = (string) $orderElement->FLAGS;
        }
    }

    protected function addInsertFieldItem(&$itemData, $item)
    {
        $itemData['pohoda_id'] = (string) $item->POHODA_ID;
    }

    protected function updateItem($itemData, $item)
    {
        sqlQueryBuilder()
            ->update('order_items')
            ->directValues($itemData)
            ->andWhere('pohoda_id=:id')
            ->setParameter('id', (string) $item->POHODA_ID)
            ->execute();
    }

    protected function existsItemInArray($selectedItems, $item)
    {
        foreach ($selectedItems as $i) {
            if ((string) $item->POHODA_ID == $i['pohoda_id'] || (string) $item->NAME == $i['descr']) {
                return $i['id'];
            }
        }

        return null;
    }

    protected function afterInsertAction($orderElement, $order)
    {
        $this->resolveOrder($orderElement, $order->id);
    }

    protected function afterOrderUpdateAction($orderElement, $order)
    {
        $this->resolveOrder($orderElement, $order->id);

        if ($this->bonusComputer) {
            $this->bonusComputer->updateBonusPoints($order);
        }
    }

    /**
     * @required
     */
    public function setBonusComputer(?BonusComputer $bonusComputer)
    {
        $this->bonusComputer = $bonusComputer;
    }
}
