/***************************************************************************
 *   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 impgnced 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 ledger import / export.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgimportpluginledger.h"

#include <klocalizedstring.h>
#include <kpluginfactory.h>

#include <qsavefile.h>

#include "skgbankincludes.h"
#include "skgdocumentbank.h"
#include "skgservices.h"
#include "skgtraces.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGImportPluginLedgerFactory, registerPlugin<SKGImportPluginLedger>();)

SKGImportPluginLedger::SKGImportPluginLedger(QObject* iImporter, const QVariantList& iArg)
    : SKGImportPlugin(iImporter)
{
    SKGTRACEINFUNC(10)
    Q_UNUSED(iArg)
}

SKGImportPluginLedger::~SKGImportPluginLedger()
    = default;

bool SKGImportPluginLedger::isExportPossible()
{
    SKGTRACEINFUNC(10)
    return (m_importer == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("LEDGER"));
}

SKGError SKGImportPluginLedger::exportFile()
{
    SKGError err;
    QSaveFile file(m_importer->getLocalFileName(false));
    if (!file.open(QIODevice::WriteOnly)) {
        err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Save file '%1' failed", m_importer->getFileName().toDisplayString()));
    } else {
        auto listUUIDs = SKGServices::splitCSVLine(m_exportParameters.value(QStringLiteral("uuid_of_selected_accounts_or_operations")));

        QString wc;
        for (const auto& uuid : listUUIDs) {
            auto items = SKGServices::splitCSVLine(uuid, '-');
            if (items.at(1) == QStringLiteral("operation")) {
                if (!wc.isEmpty()) {
                    wc += QLatin1String(" AND ");
                }
                wc += " i_OPID=" + items.at(0);
            } else if (items.at(1) == QStringLiteral("account")) {
                if (!wc.isEmpty()) {
                    wc += QLatin1String(" AND ");
                }
                wc += " rd_account_id=" + items.at(0);
            }
        }
        if (wc.isEmpty()) {
            wc = QStringLiteral("1=1");
        }  else {
            IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message",  "Only selected accounts and operations have been exported")))
        }

        QLocale en(QStringLiteral("en_EN"));
        QTextStream stream(&file);
        if (!m_importer->getCodec().isEmpty()) {
            stream.setCodec(m_importer->getCodec().toLatin1().constData());
        }
        stream << "; -*- ledger file generated by Skrooge -*-" << Qt::endl;
        err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export %1 file", "ledger"), 2);
        IFOK(err) {
            auto punit = m_importer->getDocument()->getPrimaryUnit();
            SKGObjectBase::SKGListSKGObjectBase units;
            err = m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type NOT IN ('C', '1', '2')"), units);
            int nb = units.count();
            IFOK(err) {
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    SKGUnitObject unit(units.at(i));
                    QString qs = en.toCurrencyString(SKGServices::stringToDouble(unit.getAttribute(QStringLiteral("f_CURRENTAMOUNT"))), punit.Symbol, punit.NbDecimal);
                    stream << "P " << SKGServices::dateToSqlString(QDate::currentDate()).replace('-', '/')
                           << " \"" << unit.getSymbol() << '"'
                           << " " << qs
                           << Qt::endl;
                    stream << Qt::endl;

                    IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
                }

                SKGENDTRANSACTION(m_importer->getDocument(),  err)
            }
        }

        IFOKDO(err, m_importer->getDocument()->stepForward(1))

        IFOK(err) {
            SKGObjectBase::SKGListSKGObjectBase operations;
            err = m_importer->getDocument()->getObjects(QStringLiteral("v_operation"), wc % QStringLiteral(" AND t_template='N' ORDER BY d_date"), operations);
            int nb = operations.count();
            IFOK(err) {
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export operations"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    SKGOperationObject op(operations.at(i));
                    auto status = op.getStatus();
                    auto number = op.getNumber();

                    SKGPayeeObject payee;
                    op.getPayee(payee);

                    SKGUnitObject unit;
                    op.getUnit(unit);
                    bool isCurrency = unit.getType() == SKGUnitObject::CURRENCY || unit.getType() == SKGUnitObject::PRIMARY || unit.getType() == SKGUnitObject::SECONDARY;

                    auto payeeString = payee.getName();
                    if (payeeString.isEmpty()) {
                        payeeString = op.getComment();
                    }

                    auto nbDec = SKGServices::stringToInt(op.getAttribute(QStringLiteral("i_NBDEC")));
                    if (nbDec == 0) {
                        nbDec = 2;
                    }
                    QString symbol = unit.getSymbol();
                    if (symbol.contains(QStringLiteral(" "))) {
                        symbol = '"' + symbol + '"';
                    }
                    QString qs = en.toCurrencyString(SKGServices::stringToDouble(op.getAttribute(QStringLiteral("f_QUANTITY"))), QStringLiteral(" "), nbDec);
                    if (isCurrency) {
                        qs = symbol + qs;
                    } else {
                        qs = qs + ' ' + symbol;
                    }

                    stream << SKGServices::dateToSqlString(op.getDate()).replace('-', '/')
                           << (status == SKGOperationObject::CHECKED ? " *" : status == SKGOperationObject::POINTED ? " !" : "")
                           << (!number.isEmpty() ? QStringLiteral(" (") % number % ")" : QString())
                           << QStringLiteral(" ") << payeeString
                           << Qt::endl;
                    stream << "  ; Skrooge ID: " << op.getID() << Qt::endl;
                    stream << "  ; Import ID: " << op.getImportID() << Qt::endl;
                    auto properties = op.getProperties();
                    for (const auto& p : qAsConst(properties)) {
                        stream << "  ; " << p << ": " << op.getProperty(p) << Qt::endl;
                    }
                    stream << "  " << i18nc("The default category for the accounts for ledger export", "Account") << ':' << op.getAttribute(QStringLiteral("t_ACCOUNT"))
                           << "  " << qs
                           << Qt::endl;

                    SKGObjectBase::SKGListSKGObjectBase suboperations;
                    IFOKDO(err, op.getSubOperations(suboperations))
                    int nbsuboperations = suboperations.count();
                    for (int j = 0; !err && j < nbsuboperations; ++j) {
                        SKGSubOperationObject sop(suboperations.at(j));
                        SKGCategoryObject cat;
                        sop.getCategory(cat);
                        auto catString = cat.getFullName().replace(OBJECTSEPARATOR, QLatin1String(":"));
                        if (catString.isEmpty()) {
                            catString = i18nc("Category not defined", "Not defined");
                        }
                        QString qs = en.toCurrencyString(-sop.getQuantity(), QStringLiteral(" "), nbDec);
                        if (isCurrency) {
                            qs = unit.getSymbol() + qs;
                        } else {
                            qs = qs + ' ' + unit.getSymbol();
                        }

                        stream << "  " << i18nc("The default category for the categories for ledger export", "Category") << ':' <<  catString
                               << "  " << qs;
                        if (sop.getDate() != op.getDate()) {
                            stream << "  ; [=" << SKGServices::dateToSqlString(sop.getDate()).replace('-', '/') << "]";
                        }

                        auto comment = sop.getComment();
                        if (!comment.isEmpty()) {
                            stream << "  ;comment=" << comment;
                        }
                        stream << "  ; Skrooge ID: " << sop.getID();
                        stream << Qt::endl;
                    }
                    stream << Qt::endl;

                    IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
                }

                SKGENDTRANSACTION(m_importer->getDocument(),  err)
            }
        }

        IFOKDO(err, m_importer->getDocument()->stepForward(2))

        SKGENDTRANSACTION(m_importer->getDocument(),  err)

        // Close file
        file.commit();
    }
    return err;
}

QString SKGImportPluginLedger::getMimeTypeFilter() const
{
    return "*.ledger|" % i18nc("A file format", "Ledger file");
}

#include <skgimportpluginledger.moc>
