/***************************************************************************
 *   Copyright (C) 2020 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program. If not, see <https://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * This file is Skrooge plugin for operation management.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgoperationboardwidget.h"

#include <qdom.h>
#include <qparallelanimationgroup.h>
#include <qpropertyanimation.h>
#include <qaction.h>
#include <qwidgetaction.h>

#include <kcolorscheme.h>

#include "skgdocumentbank.h"
#include "skgmainpanel.h"
#include "skgobjectbase.h"
#include "skgperiodedit.h"
#include "skgreportbank.h"
#include "skgservices.h"
#include "skgtraces.h"

SKGOperationBoardWidget::SKGOperationBoardWidget(QWidget* iParent, SKGDocument* iDocument)
    : SKGBoardWidget(iParent, iDocument, i18nc("Dashboard widget title", "Income & Expenditure")),
      m_periodEdit1(nullptr), m_periodEdit2(nullptr), m_anim(nullptr)
{
    SKGTRACEINFUNC(10)

    m_timer.setSingleShot(true);
    connect(&m_timer, &QTimer::timeout, this, [ = ]() {
        this->dataModified();
    }, Qt::QueuedConnection);

    // Initialize animation group
    m_anim = new QParallelAnimationGroup(this);

    auto f = new QFrame();
    ui.setupUi(f);
    setMainWidget(f);
    KColorScheme scheme(QPalette::Normal, KColorScheme::Window);
    auto color = scheme.foreground(KColorScheme::NormalText).color().name().right(6);

    ui.kIncomeLabel->setText("<a href=\"IC\" style=\"color: #" % color % "\">" % ui.kIncomeLabel->text() % "</a>");
    ui.kExpenseLabel->setText("<a href=\"EC\" style=\"color: #" % color % "\">" % ui.kExpenseLabel->text() % "</a>");
    ui.kSavingLabel->setText("<a href=\"SC\" style=\"color: #" % color % "\">" % ui.kSavingLabel->text() % "</a>");
    ui.kIncome_previousLabel->setText("<a href=\"IP\" style=\"color: #" % color % "\">" % ui.kIncome_previousLabel->text() % "</a>");
    ui.kExpense_previousLabel->setText("<a href=\"EP\" style=\"color: #" % color % "\">" % ui.kExpense_previousLabel->text() % "</a>");
    ui.kSaving_previousLabel->setText("<a href=\"SP\" style=\"color: #" % color % "\">" % ui.kSaving_previousLabel->text() % "</a>");

    connect(ui.kIncomeLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);
    connect(ui.kExpenseLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);
    connect(ui.kSavingLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);
    connect(ui.kIncome_previousLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);
    connect(ui.kExpense_previousLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);
    connect(ui.kSaving_previousLabel, &QLabel::linkActivated, this, &SKGOperationBoardWidget::onOpen);

    // Create menu
    setContextMenuPolicy(Qt::ActionsContextMenu);

    QStringList overlayopen;
    overlayopen.push_back(QStringLiteral("quickopen"));
    m_menuOpen = new QAction(SKGServices::fromTheme(QStringLiteral("view-statistics"), overlayopen), i18nc("Verb", "Open report..."), this);
    connect(m_menuOpen, &QAction::triggered, SKGMainPanel::getMainPanel(), [ = ]() {
        SKGMainPanel::getMainPanel()->SKGMainPanel::openPage();
    });
    addAction(m_menuOpen);

    {
        auto sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }
    m_menuGroup = new QAction(i18nc("Noun, a type of operations", "Grouped"), this);
    m_menuGroup->setCheckable(true);
    m_menuGroup->setChecked(false);
    connect(m_menuGroup, &QAction::triggered, this, &SKGOperationBoardWidget::refreshDelayed);
    addAction(m_menuGroup);

    m_menuTransfer = new QAction(i18nc("Noun, a type of operations", "Transfers"), this);
    m_menuTransfer->setCheckable(true);
    m_menuTransfer->setChecked(false);
    connect(m_menuTransfer, &QAction::triggered, this, &SKGOperationBoardWidget::refreshDelayed);
    addAction(m_menuTransfer);

    connect(m_menuGroup, &QAction::toggled, m_menuTransfer, &QAction::setEnabled);

    m_menuTracked = new QAction(i18nc("Noun, a type of operations", "Tracked"), this);
    m_menuTracked->setCheckable(true);
    m_menuTracked->setChecked(true);
    connect(m_menuTracked, &QAction::triggered, this, &SKGOperationBoardWidget::refreshDelayed);
    addAction(m_menuTracked);

    m_menuSuboperation = new QAction(i18nc("Noun, a type of operations", "On suboperations"), this);
    m_menuSuboperation->setCheckable(true);
    m_menuSuboperation->setChecked(false);
    connect(m_menuSuboperation, &QAction::triggered, this, &SKGOperationBoardWidget::refreshDelayed);
    addAction(m_menuSuboperation);

    {
        auto sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }

    m_periodEdit1 = new SKGPeriodEdit(this, true);
    m_periodEdit1->setObjectName(QStringLiteral("m_periodEdit1"));
    {
        // Set default
        QDomDocument doc(QStringLiteral("SKGML"));
        QDomElement root = doc.createElement(QStringLiteral("parameters"));
        doc.appendChild(root);
        root.setAttribute(QStringLiteral("period"), SKGServices::intToString(static_cast<int>(SKGPeriodEdit::CURRENT)));
        m_periodEdit1->setState(doc.toString());

        // Add widget in menu
        auto periodEditWidget = new QWidgetAction(this);
        periodEditWidget->setObjectName(QStringLiteral("m_periodEdit1Action"));
        periodEditWidget->setDefaultWidget(m_periodEdit1);

        addAction(periodEditWidget);
    }

    {
        auto sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }

    m_periodEdit2 = new SKGPeriodEdit(this, true);
    m_periodEdit2->setObjectName(QStringLiteral("m_periodEdit2"));
    {
        // Set default
        QDomDocument doc(QStringLiteral("SKGML"));
        QDomElement root = doc.createElement(QStringLiteral("parameters"));
        doc.appendChild(root);
        root.setAttribute(QStringLiteral("period"), SKGServices::intToString(static_cast<int>(SKGPeriodEdit::PREVIOUS)));
        m_periodEdit2->setState(doc.toString());

        // Add widget in menu
        auto periodEditWidget = new QWidgetAction(this);
        periodEditWidget->setObjectName(QStringLiteral("m_periodEdit2Action"));
        periodEditWidget->setDefaultWidget(m_periodEdit2);

        addAction(periodEditWidget);
    }

    // Refresh
    connect(m_periodEdit1, &SKGPeriodEdit::changed, this, &SKGOperationBoardWidget::refreshDelayed, Qt::QueuedConnection);
    connect(m_periodEdit2, &SKGPeriodEdit::changed, this, &SKGOperationBoardWidget::refreshDelayed, Qt::QueuedConnection);
    connect(getDocument(), &SKGDocument::tableModified, this, &SKGOperationBoardWidget::dataModified, Qt::QueuedConnection);
}

SKGOperationBoardWidget::~SKGOperationBoardWidget()
{
    SKGTRACEINFUNC(10)
    m_menuGroup = nullptr;
    m_menuTransfer = nullptr;
    m_menuTracked = nullptr;
    m_anim = nullptr;
}

QString SKGOperationBoardWidget::getState()
{
    QDomDocument doc(QStringLiteral("SKGML"));
    doc.setContent(SKGBoardWidget::getState());
    QDomElement root = doc.documentElement();

    root.setAttribute(QStringLiteral("menuGroup"), (m_menuGroup != nullptr) && m_menuGroup->isChecked() ? QStringLiteral("Y") : QStringLiteral("N"));
    root.setAttribute(QStringLiteral("menuTransfert"), (m_menuTransfer != nullptr) && m_menuTransfer->isChecked() ? QStringLiteral("Y") : QStringLiteral("N"));
    root.setAttribute(QStringLiteral("menuTracked"), (m_menuTracked != nullptr) && m_menuTracked->isChecked() ? QStringLiteral("Y") : QStringLiteral("N"));
    root.setAttribute(QStringLiteral("menuSuboperation"), (m_menuSuboperation != nullptr) && m_menuSuboperation->isChecked() ? QStringLiteral("Y") : QStringLiteral("N"));
    root.setAttribute(QStringLiteral("period1"), m_periodEdit1 != nullptr ? m_periodEdit1->getState() : QLatin1String(""));
    root.setAttribute(QStringLiteral("period2"), m_periodEdit2 != nullptr ? m_periodEdit2->getState() : QLatin1String(""));
    return doc.toString();
}

void SKGOperationBoardWidget::setState(const QString& iState)
{
    SKGBoardWidget::setState(iState);

    QDomDocument doc(QStringLiteral("SKGML"));
    doc.setContent(iState);
    QDomElement root = doc.documentElement();
    if (m_menuGroup != nullptr) {
        QString val = root.attribute(QStringLiteral("menuGroup"));
        if (val.isEmpty()) {
            val = root.attribute(QStringLiteral("menuTransfert"));
        }
        m_menuGroup->setChecked(val == QStringLiteral("Y"));
    }
    if (m_menuTransfer != nullptr) {
        m_menuTransfer->setChecked(root.attribute(QStringLiteral("menuTransfert")) == QStringLiteral("Y"));
    }
    if (m_menuTracked != nullptr) {
        m_menuTracked->setChecked(root.attribute(QStringLiteral("menuTracked")) != QStringLiteral("N"));
    }
    if (m_menuSuboperation != nullptr) {
        m_menuSuboperation->setChecked(root.attribute(QStringLiteral("menuSuboperation")) == QStringLiteral("Y"));
    }
    QString period1 = root.attribute(QStringLiteral("period1"));
    if ((m_periodEdit1 != nullptr) && !period1.isEmpty()) {
        m_periodEdit1->setState(period1);
    }
    QString period2 = root.attribute(QStringLiteral("period2"));
    if ((m_periodEdit2 != nullptr) && !period2.isEmpty()) {
        m_periodEdit2->setState(period2);
    }
    refreshDelayed();
}

void SKGOperationBoardWidget::onOpen(const QString& iLink)
{
    bool onSubOperation = ((m_menuSuboperation != nullptr) && m_menuSuboperation->isChecked());

    // Call operation plugin
    QString wc;
    if (iLink.endsWith(QLatin1String("C"))) {
        wc = m_periodEdit1->getWhereClause() % " AND t_TYPEACCOUNT<>'L'";
    } else {
        wc = m_periodEdit2->getWhereClause() % " AND t_TYPEACCOUNT<>'L'";
    }

    if (iLink.startsWith(QLatin1String("I"))) {
        wc = wc % " AND t_TYPEEXPENSE='+'";
    } else if (iLink.startsWith(QLatin1String("E"))) {
        wc = wc % " AND t_TYPEEXPENSE='-'";
    }

    wc = wc % ((m_menuGroup != nullptr) && m_menuGroup->isChecked() ? "" : " AND i_group_id=0") % ((m_menuTransfer != nullptr) && m_menuTransfer->isChecked() ? "" : " AND t_TRANSFER='N'") % ((m_menuTracked != nullptr) && m_menuTracked->isChecked() ? "" : (onSubOperation ? " AND t_REALREFUND=''" : " AND t_REFUND=''"));

    QString title;
    if (iLink == QStringLiteral("IC")) {
        title = i18nc("Title of a list of operations", "Incomes of %1", ui.kLabel->text());
    } else if (iLink == QStringLiteral("EC")) {
        title = i18nc("Title of a list of operations", "Expenses of %1", ui.kLabel->text());
    } else if (iLink == QStringLiteral("SC")) {
        title = i18nc("Title of a list of operations", "Savings of %1", ui.kLabel->text());
    } else if (iLink == QStringLiteral("IP")) {
        title = i18nc("Title of a list of operations", "Incomes of %1", ui.kLabel_previous->text());
    } else if (iLink == QStringLiteral("EP")) {
        title = i18nc("Title of a list of operations", "Expenses of %1", ui.kLabel_previous->text());
    } else if (iLink == QStringLiteral("SP")) {
        title = i18nc("Title of a list of operations", "Savings of %1", ui.kLabel_previous->text());
    }
    SKGMainPanel::getMainPanel()->openPage("skg://skrooge_operation_plugin/" % QString(onSubOperation ? QStringLiteral("SKGOPERATION_CONSOLIDATED_DEFAULT_PARAMETERS/") : QString()) % "?operationTable=" % SKGServices::encodeForUrl(onSubOperation ? QStringLiteral("v_suboperation_consolidated") : QStringLiteral("v_operation_display")) % "&title_icon=view-bank-account&currentPage=-1&title=" % SKGServices::encodeForUrl(title) %
                                           "&operationWhereClause=" % SKGServices::encodeForUrl(wc));
}

void SKGOperationBoardWidget::refreshDelayed()
{
    m_timer.start(300);
}

void SKGOperationBoardWidget::dataModified(const QString& iTableName, int iIdTransaction)
{
    SKGTRACEINFUNC(10)
    Q_UNUSED(iIdTransaction)
    QString table = ((m_menuSuboperation != nullptr) && m_menuSuboperation->isChecked() ? QStringLiteral("v_suboperation_consolidated") : QStringLiteral("v_operation_display"));
    if ((m_periodEdit1 != nullptr) && (m_periodEdit2 != nullptr) && (iTableName == table || iTableName.isEmpty())) {
        // Set titles
        ui.kLabel->setText(m_periodEdit1->text());
        ui.kLabel_previous->setText(m_periodEdit2->text());

        auto* doc = qobject_cast<SKGDocumentBank*>(getDocument());
        if (doc != nullptr) {
            if (m_menuOpen != nullptr) {
                QString url = QStringLiteral("skg://skrooge_report_plugin/?grouped=") % ((m_menuGroup != nullptr) && m_menuGroup->isChecked() ? QStringLiteral("Y") : QStringLiteral("N")) % "&transfers="
                              % ((m_menuTransfer != nullptr) && m_menuTransfer->isChecked() ? QStringLiteral("Y") : QStringLiteral("N")) % "&tracked="
                              % ((m_menuTracked != nullptr) && m_menuTracked->isChecked() ? QStringLiteral("Y") : QStringLiteral("N")) % "&expenses=Y&incomes=Y&lines2=t_TYPEEXPENSENLS&columns=d_DATEMONTH&currentPage=-1" %
                              "&mode=0&interval=3&period=3" %
                              "&tableAndGraphState.graphMode=1&tableAndGraphState.allPositive=Y&tableAndGraphState.show=graph&title=" %
                              SKGServices::encodeForUrl(i18nc("Noun, the title of a section", "Income & Expenditure"));
                m_menuOpen->setData(url);
            }

            SKGServices::SKGUnitInfo primary = doc->getPrimaryUnit();
            SKGServices::SKGUnitInfo secondary = doc->getSecondaryUnit();

            auto* bk = qobject_cast< SKGReportBank* >(doc->getReport());
            if (bk != nullptr) {
                QVariantList table2 = bk->getIncomeVsExpenditure((m_menuSuboperation != nullptr) && m_menuSuboperation->isChecked(),
                                      (m_menuGroup != nullptr) && m_menuGroup->isChecked(),
                                      (m_menuTransfer != nullptr) && m_menuTransfer->isChecked(),
                                      (m_menuTracked != nullptr) && m_menuTracked->isChecked(),
                                      m_periodEdit1->getWhereClause(),
                                      m_periodEdit2->getWhereClause());
                delete bk;

                QVariantList l1 = table2.value(1).toList();
                QVariantList l2 = table2.value(2).toList();
                double income_previous_month = l1.value(2).toDouble();
                double expense_previous_month = l2.value(2).toDouble();
                double income_month = l1.value(3).toDouble();
                double expense_month = l2.value(3).toDouble();

                // Set Maximum
                int max = qMax(income_previous_month, qMax(expense_previous_month, qMax(income_month, expense_month)));
                if (max == 0) {
                    max = 100.0;
                }
                ui.kIncome->setMaximum(max);
                ui.kIncome_previous->setMaximum(max);
                ui.kExpense->setMaximum(max);
                ui.kExpense_previous->setMaximum(max);
                ui.kSaving->setMaximum(max);
                ui.kSaving_previous->setMaximum(max);

                // Set texts and tool tips
                ui.kIncome->setFormat(doc->formatMoney(income_month, primary, false));
                ui.kIncome_previous->setFormat(doc->formatMoney(income_previous_month, primary, false));
                ui.kExpense->setFormat(doc->formatMoney(expense_month, primary, false));
                ui.kExpense_previous->setFormat(doc->formatMoney(expense_previous_month, primary, false));
                ui.kSaving->setFormat(doc->formatMoney(income_month - expense_month, primary, false));
                ui.kSaving_previous->setFormat(doc->formatMoney(income_previous_month - expense_previous_month, primary, false));
                if (!secondary.Symbol.isEmpty() && (secondary.Value != 0.0)) {
                    ui.kIncome->setToolTip(doc->formatMoney(income_month, secondary, false));
                    ui.kIncome_previous->setToolTip(doc->formatMoney(income_previous_month, secondary, false));
                    ui.kExpense->setToolTip(doc->formatMoney(expense_month, secondary, false));
                    ui.kExpense_previous->setToolTip(doc->formatMoney(expense_previous_month, secondary, false));
                    ui.kSaving->setToolTip(doc->formatMoney(income_month - expense_month, secondary, false));
                    ui.kSaving_previous->setToolTip(doc->formatMoney(income_previous_month - expense_previous_month, secondary, false));
                }

                // Change colors
                ui.kIncome->setLimits(0, 0, max);
                ui.kIncome_previous->setLimits(0, 0, max);
                ui.kExpense->setLimits(max, -1, -1);
                ui.kExpense_previous->setLimits(max, -1, -1);
                ui.kSaving->setLimits(income_month - expense_month < 0 ? max : 0, 0.1 * income_month, max);
                ui.kSaving_previous->setLimits(income_previous_month - expense_previous_month < 0 ? max : 0, 0.1 * income_previous_month, max);

                // Set values
                if (m_anim != nullptr) {
                    m_anim->clear();
                }
                SKGOperationBoardWidget::setValue(ui.kIncome, income_month);
                SKGOperationBoardWidget::setValue(ui.kIncome_previous, income_previous_month);
                SKGOperationBoardWidget::setValue(ui.kExpense, expense_month);
                SKGOperationBoardWidget::setValue(ui.kExpense_previous, expense_previous_month);
                SKGOperationBoardWidget::setValue(ui.kSaving, qAbs(income_month - expense_month));
                SKGOperationBoardWidget::setValue(ui.kSaving_previous, qAbs(income_previous_month - expense_previous_month));
                if (m_anim != nullptr) {
                    QTimer::singleShot(1000, Qt::CoarseTimer, m_anim, [ = ]() {
                        m_anim->start();
                    });
                }
            }

            // No widget if no account
            bool exist = false;
            doc->existObjects(QStringLiteral("account"), QLatin1String(""), exist);
            if (parentWidget() != nullptr) {
                setVisible(exist);
            }
        }
    }
}

void SKGOperationBoardWidget::setValue(SKGProgressBar* iWidget, double iValue)
{
    if (m_anim != nullptr) {
        auto panim = new QPropertyAnimation(iWidget, "value");
        panim->setDuration(1000);
        panim->setStartValue(0);
        panim->setEndValue(static_cast<int>(iValue));
        m_anim->addAnimation(panim);
    } else {
        iWidget->setValue(iValue);
    }
}

