<?php

namespace KupShop\HeurekaCartBundle\Services;

use KupShop\KupShopBundle\Config;
use KupShop\OrderingBundle\Event\OrderEvent;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;

class OrderSend extends HeurekaService
{
    use \DatabaseCommunication;

    /** @required */
    public OrderInfo $orderInfo;

    /** @required */
    public EventDispatcherInterface $eventDispatcher;

    public function getResponse(Request $request): array
    {
        // $order_data = $request->query->all();
        $order_data = $request->request->all();

        $response = null;

        $heureka_id = $order_data['heureka_id'];
        $like = '%\"heureka_id\":\"'.$heureka_id.'\"%';
        $qb = sqlQueryBuilder()->select('id, order_no')->from('orders')
            ->where('date_created > (CURDATE() - INTERVAL 1 DAY)')
            ->andWhere(Operator::like(['note_admin' => $like]));
        $order = $qb->execute()->fetch();
        if ($order) {
            $response['order_id'] = intval($order['id']);
            $response['internal_id'] = $order['order_no'];
            $response['variableSymbol'] = intval($order['order_no']);

            return $response;
        }

        $products = null;
        foreach ($order_data['products'] as $product) {
            $prod = $this->settings->getProductByID($product['id']);
            if (!$prod) {
                $error = $this->returnError(404, "Neexistující produkt/varianta v objednávce (id={$product['id']}).");

                return $error;
            }

            $product['product'] = $prod;
            $products[] = $product;

            if (!empty($product['gifts'])) {
                foreach ($product['gifts'] as $gift) {
                    if (!empty($gift['shopGiftId'])) {
                        $gift_prod = $this->settings->getProductByID($gift['shopGiftId']);
                        if ($gift_prod) {
                            $gift_product = ['id' => $gift['shopGiftId'], 'count' => 1, 'price' => 0, 'totalPrice' => 0, 'product' => $gift_prod];
                            $products[] = $gift_product;
                        }
                    }
                }
            }
        }

        $deliveryId = $order_data['deliveryId'] ?? null;
        $paymentId = $order_data['paymentId'] ?? null;
        if ($paymentId === 0) {
            $paymentId = $this->settings->getHeurekaPayment();
        }
        $deliveryType = null;
        if ($deliveryId && $paymentId) {
            foreach (\DeliveryType::getAll(true) as $delivery_type) {
                if ($delivery_type->id_delivery == $deliveryId && $delivery_type->id_payment == $paymentId) {
                    $deliveryType = $delivery_type;
                    break;
                }
            }
        }

        $message = 'Neexistující doprava/platba v objednávce.';
        if (!$deliveryType) {
            $deliveryType = $this->settings->getHeurekaDeliveryType($deliveryId);
            if ($deliveryId === null) {
                $message = 'Neexistující doprava v objednávce.';
            }
        }

        if (!$deliveryType) {
            $error = $this->returnError(404, $message);

            return $error;
        }

        $note = getVal('note', $order_data);

        $currency = $this->settings->getCurrency();
        $language = $this->settings->getLanguage();

        $user = new \User();
        $user->email = $order_data['customer']['email'];
        $user->id_language = $language->getId();
        $country = $this->checkCountry($order_data['customer']['state']);
        $zip = str_replace(' ', '', $order_data['customer']['postCode']);
        $invoice = [
            'name' => $order_data['customer']['firstname'],
            'surname' => $order_data['customer']['lastname'],
            'firm' => $order_data['customer']['company'],
            'street' => $order_data['customer']['street'],
            'city' => $order_data['customer']['city'],
            'zip' => $zip,
            'country' => $country,
            'ico' => $order_data['customer']['ic'] ?? '',
            'dic' => $order_data['customer']['dic'] ?? '',
            'phone' => $order_data['customer']['phone'],
            'email' => $order_data['customer']['email'],
            'currency' => $currency->getId(),
        ];
        $country = $this->checkCountry($order_data['deliveryAddress']['state']);
        $zip = str_replace(' ', '', $order_data['deliveryAddress']['postCode']);
        $delivery = [
            'name' => $order_data['deliveryAddress']['firstname'],
            'surname' => $order_data['deliveryAddress']['lastname'],
            'firm' => $order_data['deliveryAddress']['company'],
            'street' => $order_data['deliveryAddress']['street'],
            'city' => $order_data['deliveryAddress']['city'],
            'zip' => $zip,
            'country' => $country,
            'currency' => $currency->getId(),
        ];
        $requires_delivery = $deliveryType->requiresDeliveryAddress();

        $error = $user->updateAddresses($invoice, $delivery, !$requires_delivery);

        if ($error) {
            // send to sentry and continue
            $logger = getRaven();
            $logger->captureMessage('Heureka Cart Error', [], ['extra' => [
                'msg' => 'Nejsou správně vyplněny všechny povinné údaje.',
                'userAddressError' => $error,
            ]]);
        }

        $fields = [
            'order_no' => '_'.rand(0, 999999),
            'status' => 0,
            'source' => OrderInfo::ORDER_SOURCE_DROPSHIP,
            'invoice_name' => $user->invoice['name'] ?? '',
            'invoice_surname' => $user->invoice['surname'] ?? '',
            'invoice_firm' => $user->invoice['firm'] ?? '',
            'invoice_ico' => $user->invoice['ico'] ?? '',
            'invoice_dic' => $user->invoice['dic'] ?? '',
            'invoice_street' => $user->invoice['street'] ?? '',
            'invoice_city' => $user->invoice['city'] ?? '',
            'invoice_zip' => $user->invoice['zip'] ?? '',
            'invoice_country' => $user->invoice['country'] ?? '',
            'invoice_phone' => $user->invoice['phone'] ?? '',
            'invoice_email' => $user->invoice['email'] ?? '',
            'invoice_state' => $user->invoice['state'] ?? '',
            'invoice_custom_address' => $user->invoice['custom_address'] ?? '',
            'delivery_name' => $user->delivery['name'] ?? '',
            'delivery_surname' => $user->delivery['surname'] ?? '',
            'delivery_firm' => $user->delivery['firm'] ?? '',
            'delivery_street' => $user->delivery['street'] ?? '',
            'delivery_city' => $user->delivery['city'] ?? '',
            'delivery_zip' => $user->delivery['zip'] ?? '',
            'delivery_country' => $user->delivery['country'] ?? '',
            'delivery_state' => $user->delivery['state'] ?? '',
            'delivery_custom_address' => $user->delivery['custom_address'] ?? '',
            'delivery_type' => $deliveryType->name,
            'id_delivery' => $deliveryType->id,
            'delivery_complete' => 0,
            'note_user' => $note,
            'date_created' => date('Y-m-d H:i:s'),
            'date_updated' => date('Y-m-d H:i:s'),
        ];

        if (findModule('currencies')) {
            $fields['id_language'] = $language->getId();
            $fields['currency'] = $currency->getId();
            $fields['currency_rate'] = $currency->getRate();
        }

        $cfg = Config::get();
        if (!empty($cfg['Order']['Flags']) && !empty($cfg['Order']['Flags']['H'])) {
            $fields['flags'] = 'H';
        }
        if (!empty($note) && !empty($cfg['Order']['Flags']) && !empty($cfg['Order']['Flags']['R'])) {
            $fields['flags'] = getVal('flags', $fields).',R';
        }

        sqlGetConnection()->transactional(function () use (&$response, $fields, $products, $deliveryType, $order_data) {
            $SQL = $this->insertSQL('orders', $fields);

            if ($SQL) {
                // ID nove ulozene objednavky
                $IDorder = sqlInsertId();

                // Create Order object
                $order = new \Order();
                $order->createFromDB($IDorder);

                // dispatch order created event - order no is generated in event subscriber
                $this->eventDispatcher->dispatch(new OrderEvent($order), OrderEvent::ORDER_CREATED);

                $order->setData('heureka_id', $order_data['heureka_id']);
                if ($deliveryType->getPayment() instanceof \HeurekaPayment) {
                    $order->setData('disable_autostorno', 1);
                    $order->setData('not_paid_notified', 99);
                }

                // Set status indicating order creation
                $order->status = -1;

                foreach ($products as $product) {
                    $prod = $product['product'];
                    $IDprod = $prod->id;
                    $IDvariation = $prod->variationId ?? null;
                    $Pieces = $product['count'];

                    $res = $order->insertItem($IDprod, $IDvariation, $Pieces, dispatchEvent: true);

                    if ($res === false) {
                        logError(__FILE__, __LINE__, "Order->insertItem failed: insertItem({$IDprod}, {$IDvariation}, {$Pieces})");
                        $order->logHistory("Order->insertItem failed: insertItem({$IDprod}, {$IDvariation}, {$Pieces})");
                    } else {
                        $item['piece_price'] = toDecimal($product['price'])->removeVat($prod->vat);
                        $item['total_price'] = $item['piece_price']->mul(toDecimal($Pieces));

                        $this->updateSQL('order_items', $item, ['id' => $res]);
                    }
                }

                $deliveryPrice = getVal('deliveryPrice', $order_data, 0);
                $paymentPrice = getVal('paymentPrice', $order_data, 0);
                $deliveryPrice = toDecimal($deliveryPrice)->add(toDecimal($paymentPrice));
                if (!$deliveryPrice->isZero() || findModule(\Modules::ORDERS, \Modules::SUB_FREE_DELIVERY_ROW)) {
                    $deliveryPrice = $deliveryPrice->removeVat(getVat());
                    $delivery_item = [
                        'id_order' => $order->id,
                        'pieces' => 1,
                        'pieces_reserved' => 1,
                        'piece_price' => $deliveryPrice,
                        'total_price' => $deliveryPrice,
                        'descr' => $deliveryType->name,
                        'tax' => getVat(),
                        'date' => date('Y-m-d H:i:s'),
                        'note' => '{"item_type":"delivery"}',
                    ];
                    $this->insertSQL('order_items', $delivery_item);
                }

                $order->recalculate(true);

                $paymentOnlineType = getVal('paymentOnlineType', $order_data);
                if ($paymentOnlineType) {
                    $order->setData('heureka_payment_data', $paymentOnlineType);
                }

                $delivery = $deliveryType->getDelivery();
                $delivery_data = null;
                if ($delivery instanceof \BalikNaPostu) {
                    $delivery_data['psc'] = $order->delivery_zip;
                }
                $depotId = getVal('depotId', $order_data['deliveryAddress']);
                if ($depotId) {
                    if ($delivery instanceof \Zasilkovna) {
                        $info = $delivery->getInfo($depotId);
                        if (empty($info['labelRouting'])) {
                            $note = 'Neznámá pobočka Zásilkovny! '.$depotId;
                            $order->logHistory($note, false, $order_data['deliveryAddress']);
                            if (empty($order->note_user)) {
                                $order->addFlag('R');
                                $this->updateSQL('orders', ['note_user' => $note], ['id' => $order->id]);
                            }
                        } else {
                            $delivery_data['idZ'] = $depotId;
                        }
                    }
                    if ($delivery instanceof \DPDPickup) {
                        $delivery_data['dpdpickup_id'] = getVal('originalId', $order_data['deliveryAddress'], $depotId);
                    }
                    if ($delivery instanceof \Balikovna) {
                        $delivery_data['zip'] = $depotId;
                        $this->updateSQL('orders', ['delivery_zip' => $depotId], ['id' => $order->id]);
                    }
                    if ($delivery instanceof \GLSParcelShop) {
                        $delivery_data['glsparcelshop_id'] = getVal('originalId', $order_data['deliveryAddress'], $depotId);
                    }
                    if ($delivery instanceof \PPLParcelShop) {
                        $delivery_data['pplparcelshop_id'] = getVal('originalId', $order_data['deliveryAddress'], $depotId);
                    }
                }
                if ($delivery_data) {
                    if (empty($delivery_data['zip'])) {
                        $delivery_data['zip'] = $order->delivery_zip;
                    }
                    $delivery->data = $delivery_data;
                    $applyToOrder = $delivery->applyToOrder($delivery_data, $order);
                    if ($applyToOrder !== true) { // applyToOrder vratila chybovou hlasku
                        $order->logHistory($applyToOrder.' '.$depotId, false, $order_data['deliveryAddress']);
                        if (empty($order->note_user)) {
                            $order->addFlag('R');
                            $this->updateSQL('orders', ['note_user' => $applyToOrder], ['id' => $order->id]);
                        }
                    } else {
                        $order->setData('delivery_data', $delivery_data);
                    }
                }

                // zaslat potvrzovaci email
                $note = getVal('note', $order_data);
                $order->changeStatus(0, str_replace(["\r\n", "\n"], '<br>', htmlentities($note)));

                $response['order_id'] = intval($order->id);
                $response['internal_id'] = $order->order_no;
                $response['variableSymbol'] = intval($order->order_no);

                // pridat vazbu do order_dropshipments
                $dropshipmentId = $this->settings->getDropshipmentId();
                if ($dropshipmentId) {
                    sqlQueryBuilder()
                    ->insert('order_dropshipment')
                    ->directValues([
                        'id_order' => $order->id,
                        'id_dropshipment' => $dropshipmentId,
                        'id_external' => $order_data['heureka_id'],
                    ])->execute();
                }
            }
        });

        return $response;
    }

    public function checkCountry(string $country): string
    {
        if ($country == 'Česká republika') {
            $country = 'CZ';
        }
        if (($country == 'Slovensko') || ($country == 'Slovenská republika')) {
            $country = 'SK';
        }

        if (($country != 'CZ') && ($country != 'SK')) {
            $country = 'CZ';
        }

        return $country;
    }
}
