/***************************************************************************
 * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
 * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
 * SPDX-License-Identifier: GPL-3.0-or-later
 ***************************************************************************/
/** @file
 * This file is Skrooge plugin for XML import / export.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgimportpluginxml.h"

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

#include <qsavefile.h>
#include <qfile.h>
#include <QtXmlPatterns/qxmlquery.h>
#include <qstandardpaths.h>

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

/**
 * This plugin factory.
 */
K_PLUGIN_CLASS_WITH_JSON(SKGImportPluginXml, "metadata.json")

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

SKGImportPluginXml::~SKGImportPluginXml()
    = default;

bool SKGImportPluginXml::isImportPossible()
{
    SKGTRACEINFUNC(10)
    if (m_importer->getDocument() == nullptr) {
        return true;
    }
    if (m_importer->getFileNameExtension() != QStringLiteral("XML")) {
        return false;
    }
    return true;
}


SKGError SKGImportPluginXml::importFile()
{
    if (m_importer->getDocument() == nullptr) {
        return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
    }
    SKGError err;
    SKGTRACEINFUNCRC(2, err)

    // Determine the XML format
    QString format;
    QDomElement docElem;
    IFOKDO(err, m_importer->getXMLDocument(docElem))
    IFOK(err) {
        if (docElem.tagName() == "skrooge") {
            // SKROOGE XML FORMAT
            format = "XML";
        } else if (docElem.tagName() == "Document") {
            // ISO20022 XML FORMAT
            QFile file(m_importer->getLocalFileName());
            if (!file.open(QIODevice::ReadOnly)) {
                err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
            } else {
                QTextStream xmlStream(file.readAll(), QIODevice::ReadOnly);
                QString xml = xmlStream.readAll().replace(QRegularExpression("<Document[^>]*>"), "<Document>");
                QString out;
                QXmlQuery query(QXmlQuery::XSLT20);
                query.setFocus(xml);
                query.setQuery(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/ISO20022.xslt"))));
                query.evaluateTo(&out);
                //SKGTRACE << "OUT=" << out << Qt::endl;

                // Set the file without uncompression
                QString errorMsg;
                int errorLine = 0;
                int errorCol = 0;
                QDomDocument doc;
                bool contentOK = doc.setContent(out, &errorMsg, &errorLine, &errorCol);

                if (!contentOK) {
                    err.setReturnCode(ERR_ABORT).setMessage(i18nc("Error message",  "%1-%2: '%3'", errorLine, errorCol, errorMsg)).addError(ERR_INVALIDARG, i18nc("Error message",  "Invalid XML content in %1", out));
                } else {
                    // Get root
                    format = "ISO20022";
                    docElem = doc.documentElement();
                }
            }
        } else {
            err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Unknown XML format. Only Skrooge and ISO20022 XML formats are supported"));
        }
    }

    // Build list of items to import
    QList<QString> types;
    types.append(QStringLiteral("unit"));
    types.append(QStringLiteral("unitvalue"));
    types.append(QStringLiteral("bank"));
    types.append(QStringLiteral("account"));
    types.append(QStringLiteral("payee"));
    types.append(QStringLiteral("refund"));
    types.append(QStringLiteral("rule"));
    types.append(QStringLiteral("category"));
    types.append(QStringLiteral("budget"));
    types.append(QStringLiteral("budgetrule"));
    types.append(QStringLiteral("operation"));
    types.append(QStringLiteral("suboperation"));
    types.append(QStringLiteral("recurrentoperation"));
    types.append(QStringLiteral("interest"));

    auto nb = types.length();
    IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", format), nb))
    for (int i = 0; !err && i < nb; ++i) {
        auto type = types.at(i);
        QDomElement itemsList = docElem.firstChildElement(QStringLiteral("list_") + type);
        IFOKDO(err, m_importer->importItems(itemsList));

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

    SKGENDTRANSACTION(m_importer->getDocument(),  err)

    IFOKDO(err, m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE")))

    return err;
}

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

SKGError SKGImportPluginXml::exportFile()
{
    SKGError err;
    QDomDocument doc;
    QVector<QString> ignore;
    ignore.append(QStringLiteral("parameters"));
    ignore.append(QStringLiteral("doctransaction"));
    ignore.append(QStringLiteral("doctransactionitem"));
    ignore.append(QStringLiteral("doctransactionmsg"));
    ignore.append(QStringLiteral("operationbalance"));
    ignore.append(QStringLiteral("budgetsuboperation"));
    ignore.append(QStringLiteral("node"));
    ignore.append(QStringLiteral("interest_result"));
    ignore.append(QStringLiteral("category.t_fullname"));
    ignore.append(QStringLiteral("operation.i_tmp"));
    ignore.append(QStringLiteral("suboperation.i_tmp"));
    ignore.append(QStringLiteral("unit.f_CURRENTAMOUNT_CACHE"));
    err = SKGServices::copySqliteDatabaseToXml(*(m_importer->getDocument()->getMainDatabase()), doc, &ignore);
    IFOK(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 {
            QTextStream stream(&file);
            if (!m_importer->getCodec().isEmpty()) {
                stream.setCodec(m_importer->getCodec().toLatin1().constData());
            }
            stream << doc.toString() << SKGENDL;

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

QString SKGImportPluginXml::getMimeTypeFilter() const
{
    return "*.xml|" % i18nc("A file format", "XML file");
}

#include <skgimportpluginxml.moc>
