#include "shopform.h"
#include "ui_shopform.h"
#include "directsaleform.h"
#include "temporaryreceiptsaveform.h"
#include "receiptsaveform.h"
#include "receiptloadform.h"
#include "paydialog.h"
#include "shopservice.h"
#include "receiptgenerator.h"
#include "paydvouchersdialog.h"
#include "isellableservice.h"
#include <QList>
#include <QSharedPointer>
#include <QSortFilterProxyModel>
#include <QMessageBox>
#include <QScrollBar>
#include <QItemSelectionModel>
#include "data/favorititem.h"
#include "favbutton.h"

#include "shop-odb.hxx"

void payVoucherFromUI(VoucherPtr voucher, PayDialog *dialog, ShopForm *form)
{
    ShopService srv;
    srv.pay(voucher);
    voucher->setEetStatus(dialog->sendToEet() ? Voucher::EET_FOR_SEND : Voucher::EET_NOT_ENTERING);
    srv.update(voucher);
    QString eetMsg;

    if (srv.isEetEnabled() && dialog->sendToEet())
    {
        bool eetRet = srv.processEet(voucher, eetMsg);

        if (!eetRet)
        {
            QString errMsg = QObject::tr("EET communication error.\n");

            if (!eetMsg.isEmpty())
            {
                errMsg += QObject::tr("Message from portal: ") + eetMsg + "\n";
            }

            errMsg += QObject::tr("Switch to offline?");

            if (srv.isEetOnline() && QMessageBox::question(NULL, QObject::tr("EET error"), errMsg) == QMessageBox::Yes)
            {
                srv.setEetOnline(false);

                if (form != NULL)
                {
                    form->setEetStatusText(srv.isEetOnline() ? QObject::tr("<a href=\"#eet\">Online</a>") : QObject::tr("<a href=\"#eet\">Offline</a>"));
                }
            }
        }
    }

    ReceiptGenerator generator;
    generator.setVoucher(voucher);
    generator.print();
}

ShopForm::ShopForm(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ShopForm)
{
    ui->setupUi(this);
    m_itemsModel = NULL;
    m_commodityModel = NULL;
    m_itemFound = false;

    ui->temporarySaveButton->setEnabled(false);
    ui->saveButton->setEnabled(false);
    ui->payButton->setEnabled(false);

    m_itemCtxMenu.reset(new QMenu());
    m_itemCtxMenu->addAction(ui->actionDelete_items);
    ui->actualReceipt->addAction(ui->actionDelete_items);

    connect(ui->actualReceipt->selectionModel(), &QItemSelectionModel::selectionChanged, [this](const QItemSelection &selected, const QItemSelection &) {
        ui->actionDelete_items->setEnabled(!selected.isEmpty());
    });
}

ShopForm::~ShopForm()
{
    delete ui;
}

void ShopForm::loadLast()
{
    if (m_itemsModel == NULL)
    {
        m_itemsModel = new AutoTableModel<VoucherItem>(this);
        m_itemsModel->setEditableCols(QList<int>() << 2);
        m_itemsModel->setTranslations(Context::instance().plugin("SHOP")->translations());
        ui->actualReceipt->setModel(m_itemsModel);
        ui->actualReceipt->setColumnHidden(0, true);
        ui->actualReceipt->setColumnHidden(3, true);
        ui->actualReceipt->setColumnHidden(4, true);

        SettingsService srv("CORE");
        GlobalSettingsPtr settings = srv.loadSettings<GlobalSettings>();

        if (!settings->vatPayer())
        {
            ui->actualReceipt->setColumnHidden(5, true);
            ui->widgetVAT->setVisible(false);
        }

        ui->actualReceipt->setColumnHidden(6, true);
        ui->actualReceipt->setColumnWidth(2, 50);
        ui->actualReceipt->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    }

    ShopService srv;
    QList<QSharedPointer<Voucher> > receipt = srv.all(QString("status = %1").arg(QString::number(Voucher::NEW)));
    if (!receipt.isEmpty())
    {
        m_voucher = receipt[0];
        srv.loadItems(m_voucher);
        m_itemsModel->setData(m_voucher->items());
        connectItemSignals();

        //ui->total->setText(QString::number(m_voucher->totalPrice().toDouble(), 'f', 2));
        setTotalText();

        if (!m_voucher->items().isEmpty())
        {
            ui->temporarySaveButton->setEnabled(true);
            ui->saveButton->setEnabled(true);
            ui->payButton->setEnabled(true);
        }
    }

    if (m_commodityModel == NULL)
    {
        m_commodityModel = new AutoTableModel<ShopItem>(this);
        m_commodityModel->setTranslations(Context::instance().plugin("SHOP")->translations());
        ui->commodityTable->setModel(m_commodityModel);

        connect(ui->commodityTable->selectionModel(), &QItemSelectionModel::currentRowChanged, [this](const QModelIndex &current, const QModelIndex &){
            ui->btnAddItem->setEnabled(current.isValid());
        });
    }

    m_commodityModel->setData(srv.allSellableItems());
    ui->commodityTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->commodityTable->setColumnHidden(4, true);
    ui->commodityTable->setColumnHidden(2, true);
    ui->commodityTable->setColumnWidth(3, 90);

    ui->commodityTable->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 30px; }");
    ui->actualReceipt->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 30px; }");

    if (srv.isEetEnabled())
    {
        ui->lblEetState->setText(srv.isEetOnline() ? tr("<a href=\"#eet\">Online</a>") : tr("<a href=\"#eet\">Offline</a>"));
    }
    else
    {
        ui->labelEete->setVisible(false);
        ui->lblEetState->setVisible(false);
    }
}

void ShopForm::loadButtons(const ShopSettingsPtr& settings)
{
    Service<FavoritItem> srvFav;
    QMap<QString, FavoritItemPtr> btnMap;

    foreach (QWidget *child, ui->favorites->findChildren<QWidget*>()) {
        if (child->objectName() != "directSale")
        {
            delete child;
        }
    }

    foreach (FavoritItemPtr item, srvFav.all()) {
        btnMap[item->favButtonName()] = item;
    }

    for (int i = 0; i < settings->favBtnRows(); i++)
    {
        for (int j = 0; j < settings->favBtnCols(); j++)
        {
            FavButton *btn = new FavButton(ui->favorites);
            QString btnName = QString::number(i) + "_" + QString::number(j);
            btn->setObjectName(btnName);

            if (settings->favBtnSize() > 0)
            {
                btn->setMinimumHeight(settings->favBtnSize());
                btn->setMinimumWidth(settings->favBtnSize());
            }
            btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
            ((QGridLayout*)ui->favorites->layout())->addWidget(btn, i + 1, j);

            if (btnMap[btnName] != nullptr)
            {
                btn->setText(btnMap[btnName]->shortName());
                connect(btn, &FavButton::clicked, [this, btnMap, btn](bool){
                    FavoritItemPtr item = btnMap[btn->objectName()];

                    IPlugin *plugin = Context::instance().plugin(item->pluginId());
                    IService *service = (plugin != nullptr ? plugin->service<IService>() : nullptr);
                    ISellableService *selSrv = dynamic_cast<ISellableService*>(service);

                    if (selSrv != nullptr)
                    {
                        addItem(selSrv->shopItem(item->refId()), 1);
                    }
                });
            }
        }
    }

     ui->commoditySearch->setFocus();
}

void ShopForm::fillRaceiptCombo()
{
    bool oldState = ui->receiptCombo->blockSignals(true);

    ShopService srv;
    QList<QSharedPointer<Voucher> > receipts = srv.all(QString("status = %1").arg(QString::number(Voucher::TEMPORARY)));

    ui->receiptCombo->clear();
    ui->receiptCombo->addItem(tr("<< empty >>"));

    foreach (QSharedPointer<Voucher> voucher, receipts) {
        ui->receiptCombo->addItem(voucher->name(), voucher->id());
    }

    ui->receiptCombo->blockSignals(oldState);
}

void ShopForm::setEetStatusText(const QString &statusText)
{
    ui->lblEetState->setText(statusText);
}

void ShopForm::setupForm()
{
    SettingsService srv("SHOP");
    ShopSettingsPtr settings = srv.loadSettings<ShopSettings>();

    ui->spnCount->setVisible(settings->showCount());
    ui->lblCount->setVisible(settings->showCount());

    loadLast();
    fillRaceiptCombo();
    loadButtons(settings);
}

void ShopForm::on_directSale_clicked()
{
    SettingsService srv("SHOP");
    ShopSettingsPtr settings = srv.loadSettings<ShopSettings>();

    DirectSaleForm *form = new DirectSaleForm(this, settings->defaultVat());
    form->setAttribute(Qt::WA_DeleteOnClose);

    connect(form, &QDialog::accepted, [this, form](){
        addItem(form->shopItem(), ((DirectSaleItem*)form->shopItem().data())->count());
    });

    form->show();
}

void ShopForm::on_temporarySaveButton_clicked()
{
    doTempSave(false);
}

void ShopForm::on_saveButton_clicked()
{
    ReceiptSaveForm *form = new ReceiptSaveForm(m_voucher, this);
    form->setAttribute(Qt::WA_DeleteOnClose);

    connect(form, &QDialog::accepted, [this, form]() {
        ShopService srv;

        if (form->saveAsNew())
        {
            m_voucher->setStatus(Voucher::NOT_PAID);
            m_voucher->setSaveDateTime(QDateTime::currentDateTime());
            srv.updateVoucher(m_voucher);
            createEmptyVoucher();
        }
        else
        {
            VoucherPtr selVoucher = form->selectedVoucher();
            srv.moveItems(m_voucher->items(), m_voucher, selVoucher);
            srv.calculate(selVoucher);
            srv.updateVoucher(selVoucher);
            createEmptyVoucher();
        }

        m_itemsModel->setData(m_voucher->items());
    });

    form->show();
}

void ShopForm::on_loadButton_clicked()
{
    ReceiptLoadForm *form = new ReceiptLoadForm(this);
    form->setAttribute(Qt::WA_DeleteOnClose);

    connect(form, &QDialog::accepted, [this, form](){
        if (form->selectedItems().isEmpty())
        {
            return;
        }

        ShopService srv;

        if (m_voucher.isNull())
        {
            m_voucher = srv.createVoucher();
        }

        srv.moveItems(form->selectedItems(), form->selectedVoucher(), this->m_voucher);
        m_voucher->setDescription(form->selectedVoucher()->description());
        m_voucher->setName(form->selectedVoucher()->name());
        m_voucher->setContact(form->selectedVoucher()->contact());

        m_itemsModel->setData(m_voucher->items());

        connectItemSignals();
        onCountChanged();
    });

    form->show();
}

void ShopForm::onCountChanged(int oldCount/* = 0*/)
{
    VoucherItem *item = qobject_cast<VoucherItem*>(sender());
    if (item != nullptr && item->count() == 0)
    {
        for (int i = 0; i < m_voucher->items().count(); i++)
        {
            if (m_voucher->items()[i].data() == item)
            {
                m_voucher->removeItem(m_voucher->items()[i]);
                m_itemsModel->setData(m_voucher->items());
            }
        }
    }

    recalculate();
    updateItemCount(item, oldCount);
}

void ShopForm::createVoucher()
{
    ShopService srv;
    m_voucher = srv.createVoucher();
}

void ShopForm::doTempSave(bool comboChanged)
{
    TemporaryReceiptSaveForm *form = new TemporaryReceiptSaveForm(m_voucher, this);
    form->setAttribute(Qt::WA_DeleteOnClose);

    connect(form, &QDialog::accepted, [this, form, comboChanged](){
        ShopService srv;

        if (!m_voucher->items().isEmpty())
        {
            m_voucher->setStatus(Voucher::TEMPORARY);
            srv.updateVoucher(m_voucher);
        }

        if (comboChanged && ui->receiptCombo->currentIndex() > 0)
        {
            changeReceipt();
        }
        else
        {
            createEmptyVoucher();
        }

        fillRaceiptCombo();

        m_itemsModel->setData(m_voucher->items());
    });

    form->show();
}

void ShopForm::changeReceipt()
{
    ShopService srv;

    m_voucher = srv.loadById(ui->receiptCombo->currentData().toInt());
    srv.loadItems(m_voucher);
    connectItemSignals();
    m_voucher->setStatus(Voucher::NEW);
    srv.updateVoucher(m_voucher);

    m_itemsModel->setData(m_voucher->items());
    //ui->total->setText(m_voucher->totalPrice().toString());
    setTotalText();

    ui->temporarySaveButton->setEnabled(true);
    ui->saveButton->setEnabled(true);
    ui->payButton->setEnabled(true);

    fillRaceiptCombo();
}

void ShopForm::connectItemSignals()
{
    foreach (QSharedPointer<VoucherItem> item, m_voucher->items()) {
        connect(item.data(), SIGNAL(countChanged(int)), this, SLOT(onCountChanged(int)));
    }
}

void ShopForm::createEmptyVoucher()
{
    ShopService srv;
    m_voucher = srv.createVoucher();
    //ui->total->setText("0");
    setTotalText();
    ui->temporarySaveButton->setEnabled(false);
    ui->saveButton->setEnabled(false);
    ui->payButton->setEnabled(false);
}

void ShopForm::addItem(QSharedPointer<IShopItem> item, int count)
{
    if (m_voucher.isNull())
    {
        createVoucher();
    }

    IPlugin *plugin = Context::instance().plugin(item->pluginId());
    IService *service = (plugin != nullptr ? plugin->service<IService>() : nullptr);
    ISellableService *selSrv = dynamic_cast<ISellableService*>(service);

    auto addFunc = [this](QSharedPointer<IShopItem> shopItem, int itemCount){
        ShopService srv;
        srv.addShopItem(m_voucher, shopItem, itemCount);
        //this->m_itemsModel->addRow(m_voucher->items()[m_voucher->items().count() - 1]);
        connect(m_voucher->items()[m_voucher->items().count() - 1].data(), SIGNAL(countChanged(int)), this, SLOT(onCountChanged(int)));
        onCountChanged();
    };

    if (selSrv != nullptr && selSrv->seller() != nullptr)
    {
        ISeller *seller = selSrv->seller();

        seller->disconnect();
        connect(seller, &ISeller::itemPrepared, addFunc);

        seller->prepareItem();
    }
    else
    {
        addFunc(item, count);
    }

    ui->actualReceipt->scrollToBottom();
    ui->commoditySearch->setFocus();
    ui->commoditySearch->setText("");
}

void ShopForm::setTotalText()
{
    ui->total->setText(QString::number(m_voucher->totalPrice().toDouble(), 'f', 2));

    ui->vatRateHigh->setText(QString::number(m_voucher->vatRateHigh().toDouble(), 'f', 0) + "%");
    ui->vatRateFirstLow->setText(QString::number(m_voucher->vatRateFirstLower().toDouble(), 'f', 0) + "%");
    ui->vatRateSecondLow->setText(QString::number(m_voucher->vatRateSecondLower().toDouble(), 'f', 0) + "%");

    ui->priceVatHigh->setText(QString::number(m_voucher->priceVatHigh().toDouble(), 'f', 2));
    ui->priceVatFirstLower->setText(QString::number(m_voucher->priceVatFirstLower().toDouble(), 'f', 2));
    ui->priceVatSecondLower->setText(QString::number(m_voucher->priceVatSecondLower().toDouble(), 'f', 2));

    ui->vatHigh->setText(QString::number((m_voucher->totalPriceVatHigh() - m_voucher->priceVatHigh()).toDouble(), 'f', 2));
    ui->vatFirstLower->setText(QString::number((m_voucher->totalPriceVatFirstLower() - m_voucher->priceVatFirstLower()).toDouble(), 'f', 2));
    ui->vatSecondLower->setText(QString::number((m_voucher->totalPriceVatSecondLower() - m_voucher->priceVatSecondLower()).toDouble(), 'f', 2));

    ui->totalPriceVatHigh->setText(QString::number(m_voucher->totalPriceVatHigh().toDouble(), 'f', 2));
    ui->totalPriceFirstLower->setText(QString::number(m_voucher->totalPriceVatFirstLower().toDouble(), 'f', 2));
    ui->totalPriceSecondLower->setText(QString::number(m_voucher->totalPriceVatSecondLower().toDouble(), 'f', 2));
    ui->priceNoVat->setText(QString::number(m_voucher->priceNoVat().toDouble(), 'f', 2));
}

void ShopForm::updateItemCount(VoucherItem *item, int oldCount)
{
    if (item != nullptr)
    {
        ShopService srv;
        int countAdded = item->count() - oldCount;
        srv.updateRelatedItem(item, countAdded);
    }
}

void ShopForm::recalculate()
{
    ShopService srv;
    srv.calculate(m_voucher);
    this->m_itemsModel->setData(m_voucher->items());

    setTotalText();
    ui->temporarySaveButton->setEnabled(!m_voucher->items().isEmpty());
    ui->saveButton->setEnabled(!m_voucher->items().isEmpty());
    ui->payButton->setEnabled(!m_voucher->items().isEmpty());

    if (m_voucher->status() == Voucher::NEW && m_voucher->id() == 0)
    {
        srv.saveVoucher(m_voucher);
    }
    else
    {
        srv.updateVoucher(m_voucher);
    }
}

void ShopForm::on_receiptCombo_currentIndexChanged(int)
{
    if (!m_voucher.isNull() && m_voucher->items().isEmpty())
    {
        ShopService srv;
        srv.erase(m_voucher);
        changeReceipt();

        return;
    }

    if (m_voucher.isNull())
    {
        changeReceipt();
    }
    else
    {
        doTempSave(true);
    }
}

void ShopForm::on_payButton_clicked()
{
    PayDialog *dialog = new PayDialog(m_voucher->totalPrice(), this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();

    connect(dialog, &QDialog::accepted, [this, dialog](){
        payVoucherFromUI(m_voucher, dialog, this);

        createEmptyVoucher();
        m_itemsModel->setData(m_voucher->items());
    });


}

void ShopForm::on_showPaiedButton_clicked()
{
    PaydVouchersDialog *dialog = new PaydVouchersDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
}

void ShopForm::on_btnAddItem_clicked()
{
    ShopItemPtr item = m_commodityModel->itemFromIndex(ui->commodityTable->currentIndex());
    addItem(item, ui->spnCount->value());
}

void ShopForm::on_commoditySearch_textChanged(const QString &text)
{
    for (int i = 0; i < 2; i++)
    {
        QString replacedText = text;

        if (i == 1)
        {
            replacedText = Helper::replaceByNumbers(text);
            //ui->commoditySearch->setText(replacedText);
        }

        QSortFilterProxyModel proxy;
        proxy.setSourceModel(m_commodityModel);
        proxy.setFilterKeyColumn(0);
        proxy.setFilterCaseSensitivity(Qt::CaseInsensitive);
        proxy.setFilterFixedString(replacedText);

        auto moveToIndex = [this](const QModelIndex &matchingIndex) {
            ui->commodityTable->scrollTo(matchingIndex,QAbstractItemView::EnsureVisible);
            ui->commodityTable->setCurrentIndex(matchingIndex);
        };

        QModelIndex matchingIndex = proxy.mapToSource(proxy.index(0,0));
        if(matchingIndex.isValid()) {
            moveToIndex(matchingIndex);
            m_itemFound = true;
            break;
        }
        else
        {
            proxy.setFilterKeyColumn(1);
            matchingIndex = proxy.mapToSource(proxy.index(0,0));

            if (matchingIndex.isValid())
            {
                moveToIndex(matchingIndex);
                m_itemFound = true;
                break;
            }
            else
            {
                m_itemFound = false;
            }
        }
    }
}

void ShopForm::on_lblEetState_linkActivated(const QString &)
{
    ShopService srv;
    srv.setEetOnline(!srv.isEetOnline());

    ui->lblEetState->setText(srv.isEetOnline() ? tr("<a href=\"#eet\">Online</a>") : tr("<a href=\"#eet\">Offline</a>"));
}

void ShopForm::on_commoditySearch_returnPressed()
{
    if (m_itemFound)
    {
        ShopItemPtr item = m_commodityModel->itemFromIndex(ui->commodityTable->currentIndex());
        addItem(item, ui->spnCount->value());
    }
    ui->commoditySearch->clear();
}

void ShopForm::on_actionDelete_items_triggered()
{
    if (QMessageBox::question(this, tr("Delete items"), tr("Realy delete selected voucher items?")) == QMessageBox::Yes) {
        QList<VoucherItemPtr> forDelete;

        for (const auto& row : ui->actualReceipt->selectionModel()->selectedIndexes()) {
            forDelete << m_itemsModel->itemFromIndex(row);
        }

        for (auto& item : forDelete) {
            m_voucher->removeItem(item);
            int oldCount = item->count();
            item->setCount(0);
            updateItemCount(item.data(), oldCount);
        }

        recalculate();
        m_itemsModel->setData(m_voucher->items());
    }
}

void ShopForm::on_actualReceipt_customContextMenuRequested(const QPoint &pos)
{
    QPoint globalPos = ui->actualReceipt->mapToGlobal(pos);
    m_itemCtxMenu->exec(globalPos);
}
