<?php

namespace KupShop\ReclamationsBundle\Admin;

use KupShop\AdminBundle\Admin\UserMessagesAdminInterface;
use KupShop\BalikonosBundle\Balikobot;
use KupShop\BalikonosBundle\Exception\BalikonosException;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\KupShopBundle\Email\UserMessagesInterface;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\OrderingBundle\Util\Order\QRPayment;
use KupShop\ReclamationsBundle\Attachment\ReclamationPDFAttachment;
use KupShop\ReclamationsBundle\Email\ReclamationMessageEmail;
use KupShop\ReclamationsBundle\Util\ReclamationsUtil;
use KupShop\ReclamationsSuppliersBundle\Util\ReclamationsSuppliersUtil;
use Query\Operator;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Reclamations extends \Window implements UserMessagesAdminInterface
{
    protected $template = 'window/reclamations.tpl';

    protected $nameField = 'code';
    protected $tableName = 'reclamations';

    /** @var ReclamationsUtil */
    public $reclamations;

    private $reclamation;
    public $contextManager;

    public function __construct()
    {
        $this->reclamations = ServiceContainer::getService(ReclamationsUtil::class);
        $this->contextManager = ServiceContainer::getService(ContextManager::class);
    }

    public function createSQLFields($tablename)
    {
        parent::createSQLFields($tablename);

        foreach ($this->fields as $key => $field) {
            if ($field == 'status') {
                unset($this->fields[$key]);
            }
        }
    }

    public function get_vars()
    {
        if (empty($this->getID())) {
            $this->action = 'add';
        }

        $vars = parent::get_vars();

        if ($this->getAction() == 'edit') {
            $order = $this->prepareOrder($vars['body']['data']['id_order']);

            $diff = 0;
            if ($order->date_handle) {
                $diff = $order->date_handle->diff(new \DateTime());
                $diff = abs($diff->days);
            }

            $vars['body']['order_date_diff'] = $diff;
            $vars['body']['order'] = $order;

            $this->contextManager->activateOrder($order, function () use (&$vars) {
                $vars['body']['emails'] = $this->reclamations->getEmails($this->getReclamation());
                $vars['body']['emailsInStatuses'] = $this->reclamations->getEmailsInStatuses($this->getReclamation());
            });

            $vars['body']['exchangeOrder'] = $this->getExchangeOrder();
            $vars['body']['returnPrice'] = toDecimal($this->getReclamation()->getItem()['total_price'])->addVat($this->getReclamation()->getItem()['tax']);
            $vars['body']['selected_delivery'] = $this->getDeliveryId();

            $delivery = $this->getDelivery();
            if ($delivery && isset($vars['body']['data']['data']['delivery_data'])) {
                $delivery->loadDeliveryInfo($vars['body']['data']['data']['delivery_data']);
            }

            $vars['body']['delivery'] = $delivery;

            if (findModule(\Modules::RECLAMATIONS_SUPPLIERS)) {
                $vars['body']['supplierReclamation'] = sqlQueryBuilder()
                    ->select('rs.id, rs.code, rs.id_supplier, rs.status, rs.date_created, rs.date_accepted, rs.date_handle')
                    ->from('reclamations_suppliers_items', 'rsi')
                    ->where(Operator::equals([
                        'id_reclamation' => $this->getID(),
                    ]))->join('rsi', 'reclamations_suppliers', 'rs', 'rs.id = rsi.id_reclamation_supplier')
                    ->execute()->fetchAssociative();

                if (findModule(\Modules::PRODUCTS_SERIAL_NUMBERS)) {
                    $vars['body']['serialNumberSuppliers'] = sqlQueryBuilder()->select('si.id_supplier')->from('products_serial_numbers',
                        'psn')
                        ->innerJoin('psn', 'stock_in', 'si', 'psn.id_stock_in = si.id')
                        ->where(Operator::equals(['psn.id_order_item' => $vars['body']['data']['id_item']]))
                        ->execute()->fetchFirstColumn();
                }
            }
        }

        if ($this->getAction() == 'add') {
            $vars['body']['data']['id_order'] = getVal('id_order', null, '');
        }

        $vars['body']['statuses'] = $this->reclamations->getStatuses();
        $vars['body']['handle_statuses'] = $this->reclamations->getHandleStatuses();
        $vars['body']['handle_types'] = $this->reclamations->getHandleTypes();
        $vars['body']['preferred_handle_types'] = $this->reclamations->getPrefHandleTypes();
        $vars['body']['address_fields'] = $this->reclamations->getAddressFields();

        $vars['body']['deliveries'] = \Delivery::getAll();

        $fakeOrder = new \Order();
        if (isset($vars['body']['data']['data']['delivery_data'])) {
            $fakeOrder->note_admin = json_encode(['delivery_data' => $vars['body']['data']['data']['delivery_data']]);
        }

        $vars['body']['fakeOrder'] = $fakeOrder;

        if (findModule(\Modules::PRODUCTS_SUPPLIERS) && $this->getAction() != 'add') {
            $item = $this->getReclamation()->getItem();
            $suppliersCodes = sqlQueryBuilder()->select('s.id, s.name, pos.code')
                ->from('products_of_suppliers', 'pos')
                ->leftJoin('pos', 'suppliers', 's', 's.id = pos.id_supplier')
                ->where(\Query\Operator::equalsNullable(['id_product' => $item['id_product'], 'id_variation' => $item['id_variation']]))
                ->execute()->fetchAll();

            $vars['body']['suppliers_codes'] = $suppliersCodes;
        }

        return $vars;
    }

    public function getExchangeOrder()
    {
        $id = $this->getReclamation() === false
            ? null
            : $this->getReclamation()->getData()['exchange_order'] ?? null;

        if ($id) {
            $order = $this->prepareOrder($id);

            return $order;
        }

        return null;
    }

    public function sendToBalikobot()
    {
        if (!findModule(\Modules::BALIKONOS)) {
            return;
        }

        $balikobot = ServiceContainer::getService(Balikobot::class);

        if ($this->getReclamation()->getIdBalikonos()) {
            return;
        }

        $address = $this->getReclamation()->getAddress();
        $deliveryId = $this->getDeliveryId();
        $deliveries = \Delivery::getAll();

        $delivery = $deliveries[$deliveryId] ?? null;

        // do not send to balikobot if in person
        if ($delivery && $delivery->isInPerson()) {
            return;
        }

        $orderCls = new \Order();
        $orderCls->currency = $this->getReclamation()->getIdCurrency();
        $orderCls->note_admin = json_encode(['delivery_data' => $this->getReclamation()->getData()['delivery_data'] ?? []]);

        $balikobot->setIDs([
            0 => [
                'type' => Balikobot::TYPE_RECLAMATION,
                'invoice_email' => $this->getReclamation()->getEmail(),
                'invoice_name' => $address['name'],
                'invoice_surname' => $address['surname'],
                'invoice_street' => $address['street'],
                'invoice_city' => $address['city'],
                'invoice_zip' => $address['zip'],
                'invoice_country' => !empty($address['country']) ? $address['country'] : 'CZ',
                'invoice_phone' => $address['phone'],
                'total_price' => $this->getReclamation()->getItem()['total_price'],
                'id_delivery' => $deliveryId,
                'cod_price' => 0,
                'order_id' => $this->getReclamation()->getCode(),
                'order' => $orderCls,
                'weight' => $this->getReclamation()->getItem()['weight'],
            ],
        ]);

        $balikobot->sendDeliveries();

        $result = $balikobot->getResult();
        $result = reset($result);

        if (!empty($result['error_message']) && $result['error_message'] != 'OK') {
            $this->returnError('Chyba při odesílání do balíkobotu: '.$result['error_message']);
        }

        $this->updateSQL('reclamations', ['package_id' => $result['package_id'] ?? null, 'id_balikonos' => $result['id_balikonos'] ?? null], ['id' => $this->getID()]);
    }

    protected function getDeliveryId()
    {
        $dbcfg = \Settings::getDefault();

        if ($this->getReclamation()) {
            $delivery = $this->reclamations->getData($this->getReclamation()->getId(), 'delivery');
            if (!empty($delivery)) {
                return $delivery;
            }

            $order = $this->prepareOrder($this->getReclamation()->getIdOrder());
            if ($order->getDeliveryType() && $order->getDeliveryType()->id_delivery != null) {
                return $order->getDeliveryType()->id_delivery;
            }
        }

        return $dbcfg->reclamations['delivery'] ?? null;
    }

    private function deleteFromBalikobot($package_id)
    {
        if (!findModule(\Modules::BALIKONOS)) {
            return;
        }

        $balikobot = ServiceContainer::getService(Balikobot::class);
        try {
            $balikobot->deletePackage($package_id);
        } catch (BalikonosException $e) {
        }

        return true;
    }

    public function getQRPayment()
    {
        $dbcfg = \Settings::getDefault();

        $returnPrice = toDecimal($this->getReclamation()->getItem()['total_price'])->addVat($this->getReclamation()->getItem()['tax']);

        $parameters = [
            'amount' => $returnPrice->asFloat(),
            'currency' => 'CZK',
            'vs' => $this->getReclamation()->getCode(),
            'message' => $dbcfg->shop_firm_name.' Reklamace '.$this->getReclamation()->getCode(),
        ];

        /** @var QRPayment $QRPayment */
        $QRPayment = ServiceContainer::getService(QRPayment::class);

        $accountNumberParameters = $QRPayment->parseAccountNumber($this->getReclamation()->getBankAccount());

        $parameters = array_merge($parameters, $accountNumberParameters);

        return $QRPayment->getQRCodeImageUrl(
            $this->prepareOrder($this->getReclamation()->getIdOrder()), 200, $parameters
        );
    }

    public function handlePrintLabel()
    {
        if (!findModule(\Modules::BALIKONOS)) {
            return;
        }

        $balikobot = ServiceContainer::getService(Balikobot::class);

        if (empty($this->getReclamation()->getIdBalikonos())) {
            $this->returnError('Štítek nelze vytisknout, protože reklamace není v balíkobotu! Zkuste reklamaci odeslat do balíkobotu znovu tím, že na detailu reklamace kliknete na tlačítko "OK"');
        }

        try {
            $balikobot->printTickets(null, 1, 'default', [], false, [$this->getReclamation()->getIdBalikonos()]);
        } catch (\KupShop\BalikonosBundle\Exception\BalikonosException $e) {
            $this->returnError($e->getMessage());
        }
    }

    public function handlePrintReclamation()
    {
        /** @var ReclamationPDFAttachment $reclamationAttachment */
        $reclamationAttachment = ServiceContainer::getService(ReclamationPDFAttachment::class);
        $reclamationAttachment->setReclamation($this->getReclamation());
        $this->contextManager->activateContexts([\KupShop\KupShopBundle\Context\LanguageContext::class => $reclamationAttachment->getReclamation()['id_language']], function () use ($reclamationAttachment) {
            header('Content-type: application/pdf');
            header('Content-Disposition: inline; filename="'.$reclamationAttachment->getFilename().'"');

            echo $reclamationAttachment->getContent();
        });
    }

    public function handleSupplierReclamation()
    {
        /**
         * @var $reclamationsSuppliersUtil ReclamationsSuppliersUtil
         */
        $reclamationsSuppliersUtil = ServiceContainer::getService(ReclamationsSuppliersUtil::class);

        $supplierId = getVal('supplierId');
        $reclamation = $this->getReclamation();

        $reclamationsSuppliersUtil->addItemFromReclamation($supplierId, $reclamation);

        $this->returnOK('Produkt přidán do reklamace k dodavateli', false, ['supplierId' => null]);
    }

    public function handleUpdate()
    {
        $data = $this->getData();

        if ($this->getAction() == 'add') {
            $delivery = [];
            foreach ($this->reclamations->getAddressFields() as $field) {
                $delivery[$field] = getVal($field, $data);
            }

            if (empty($data['id_item'])) {
                $this->returnError('Nevybrali jste položku!');
            }

            // todo: set pieces in admin
            if (empty($data['pieces'])) {
                $data['pieces'] = 1;
            }

            if ($id = $this->reclamations->createReclamation($data['id_item'], $data['pieces'], $delivery, $data['bank_account'], null, null, false)) {
                $this->setID($id);

                return true;
            }

            return false;
        } elseif ($this->getAction() == 'edit') {
            if ($delivery = $this->getDelivery()) {
                $data['data']['delivery_data'] = $delivery->storeDeliveryInfo($data['delivery_data'] ?? []);

                // Update address from delivery
                $delivery->applyToOrder($delivery_data, new \Order());
                if ($delivery_data) {
                    foreach ($delivery_data as $field => $value) {
                        $this->processedData[str_replace('delivery_', '', $field)] = $value;
                    }
                }
            }

            $return = parent::handleUpdate();

            // save data before sendToBalikobot call
            if (!empty($data['data']) && is_array($data['data'])) {
                foreach ($data['data'] as $key => $value) {
                    $this->reclamations->setData($this->getID(), $key, $value);
                }
                // Potřebuju dál pro balíkobota aktuální data, getReclamation vracelo zacachovanou verzi před updatem
                $this->reclamation = $this->reclamations->getReclamation($this->getID());
            }

            $reclamation = $this->getReclamation();
            if (!is_null($data['handle_type']) && in_array($data['handle_type'], $this->getPrintLabelHandleTypes())) {
                $this->sendToBalikobot();
            } elseif (!empty($reclamation->getIdBalikonos()) && $reclamation['status'] != 2) {
                $this->deleteFromBalikobot($this->getReclamation()->getIdBalikonos());
            }

            $userContent = ServiceContainer::getService(\KupShop\OrderingBundle\Util\UserContent\UserContent::class);
            if (($user_content = $userContent->getData('reclamation')) && $reclamation) {
                $this->reclamations->setData($this->getID(), 'userContent',
                    array_merge($reclamation->getData()['userContent'] ?? [], $user_content)
                );
                $userContent->clearData('reclamation');
            }

            $sendEmail = (!isset($data['doNotNotify'])) ? null : false;
            if (!empty($data['comment']) && !isset($data['doNotNotify'])) {
                $sendEmail = true;
            }

            if ($data['handle_type'] != null) {
                $data['status'] = ReclamationsUtil::STATUS_HANDLED;
            }

            if (isset($data['status'])) {
                $this->reclamations->changeStatus($this->getID(), $data['status'], $data['comment'], $sendEmail, $data['user_message']);
            }

            if ($data['handle_type'] == '0' || $data['handle_type'] == '2' || $data['handle_type'] == '4') {
                $this->handleConvertToReturn($data['comment'], $data['handle_type'] != '4');
            }

            return $return;
        }

        return true;
    }

    public function getPrintLabelHandleTypes()
    {
        return [1, 3];
    }

    public function handleReopen()
    {
        $data = $this->getData();
        if (empty($data['comment'])) {
            $data['comment'] = null;
        }

        $this->reclamations->changeStatus($this->getID(), 1, 'Reklamace byla znovu otevřena', false);
        $this->updateSQL('reclamations', [
            'handle_type' => null,
            'date_handle' => null,
            'package_id' => null,
            'id_balikonos' => null,
        ], ['id' => $this->getID()]);

        $this->returnOK('Reklamace byla znovu otevřena');
    }

    public function handleConvertToReturn($comment, bool $isReclamation = true)
    {
        /** @var \KupShop\ReturnsBundle\Util\ReturnsUtil $returnsUtil */
        $returnsUtil = ServiceContainer::getService(\KupShop\ReturnsBundle\Util\ReturnsUtil::class);

        $reasons = array_keys($returnsUtil->getReasons());
        $reasonId = end($reasons);
        $item = ['pieces' => $this->getReclamation()->getPieces(), 'return_reason' => $reasonId];

        $returnId = $returnsUtil->createReturn(
            $this->getReclamation()->getBankAccount() ?: '',
            [$this->getReclamation()->getIdItem() => $item],
            [],
            null,
            false
        );

        $return = $returnsUtil->getReturn($returnId);

        $returnMessage = 'Vratka byla vytvořena pro vyřízení reklamace č.';
        if (!$isReclamation) {
            $returnMessage = 'Vratka vytvořena na základě reklamace č.';
        }
        $returnsUtil->logHistory($returnId, $returnMessage." <a href=\"javascript:nw('Reclamations', {$this->getReclamation()->getId()})\">{$this->getReclamation()->getCode()}");

        $this->reclamations->setData($this->getReclamation()->getId(), 'return', $returnId);

        $reclamationMessage = 'Pro vyřízení reklamace byla vytvořena vratka č.';
        if (!$isReclamation) {
            $reclamationMessage = 'Na základě reklamace byla vytvořená vratka č.';
        }
        $this->reclamations->logHistory($this->getReclamation()->getId(), $reclamationMessage.' <a href="javascript:nw(\'Returns\', '.$returnId.')">'.$return->getCode().'</a>', false, '2');

        $orderMessage = 'Pro vyřízení reklamace č.';
        if (!$isReclamation) {
            $orderMessage = 'Na základě reklamace č.';
        }
        $order = new \Order($this->getReclamation()->getIdOrder());
        $order->createFromDB($this->getReclamation()->getIdOrder());
        $order->logHistory($orderMessage.' '.$this->getReclamation()->getId().' byla vytvořena vratka č. <a href="javascript:nw(\'Returns\', '.$returnId.')">'.$return->getCode().'</a>');

        $params = [
            's' => 'Returns.php',
            'acn' => 'edit',
            'ID' => $returnId,
        ];
        $this->redirect($params);
    }

    public function prepareOrder($orderId)
    {
        $order = new \Order();
        $order->createFromDB($orderId);

        return $order;
    }

    public function getData()
    {
        $data = parent::getData();

        if (getVal('Submit') && (!$this->getID() || !$this->getReclamation()->isClosed())) {
            if (empty($data['status'])) {
                $data['status'] = 0;
            }

            $dates = ['date_created', 'date_accepted', 'date_handle'];
            foreach ($dates as $date) {
                if (!empty($data[$date])) {
                    $data[$date] = $this->prepareDateTime($data[$date]);
                }
            }

            if (($data['handle_type'] ?? -1) < 0) {
                $data['handle_type'] = null;
            }
        }

        return $data;
    }

    protected function getReclamation()
    {
        if (!$this->reclamation) {
            $this->reclamation = $this->reclamations->getReclamation($this->getID());
        }

        return $this->reclamation;
    }

    protected function getObject()
    {
        $object = $this->getReclamation();
        if (!$object) {
            $errStr = sprintf(translate('errorNotFound', 'base'), $this->translateType(), $this->getID());
            throw new NotFoundHttpException($errStr);
        }

        return $object;
    }

    protected function getDelivery()
    {
        return \Delivery::getAll()[$this->getDeliveryId()] ?? null;
    }

    public function getUserEmails(): UserMessagesInterface
    {
        return ServiceContainer::getService(ReclamationMessageEmail::class);
    }
}

return Reclamations::class;
