/******************************************************************************
 * konsolekalendaradd.cpp                                                     *
 *                                                                            *
 * KonsoleKalendar is a command line interface to KDE calendars               *
 * SPDX-FileCopyrightText: 2002-2004 Tuukka Pasanen <illuusio@mailcity.com>   *
 * SPDX-FileCopyrightText: 2003-2005 Allen Winter <winter@kde.org>            *
 *                                                                            *
 * SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-Qt-Commercial-exception-1.0 *
 *                                                                            *
 ******************************************************************************/
/**
 * @file konsolekalendaradd.cpp
 * Provides the KonsoleKalendarAdd class definition.
 * @author Tuukka Pasanen
 * @author Allen Winter
 */
#include "konsolekalendaradd.h"

#include <CalendarSupport/KCalPrefs>

#include "konsolekalendar_debug.h"

#include <KLocalizedString>

#include <KCalendarCore/Event>
#include <KCalendarCore/FileStorage>

#include <Akonadi/Collection>
#include <Akonadi/IncidenceChanger>

#include <QElapsedTimer>
#include <QEventLoop>
#include <QObject>
#include <QTimeZone>

#include <QStandardPaths>
#include <cstdlib>
#include <iostream>

using namespace KCalendarCore;
using namespace std;

KonsoleKalendarAdd::KonsoleKalendarAdd(KonsoleKalendarVariables *vars)
{
    m_variables = vars;
}

/**
 * Adds event to Calendar
 */

bool KonsoleKalendarAdd::addEvent()
{
    bool status = true;

    if (m_variables->isDryRun()) {
        cout << i18n("Dry Run: Insert Event:").toLocal8Bit().data() << '\n';
        printSpecs();
    } else {
        if (m_variables->isVerbose()) {
            cout << i18n("Insert Event:").toLocal8Bit().data() << '\n';
            printSpecs();
        }

        Event::Ptr const event = Event::Ptr(new Event());

        const auto timeZone = m_variables->getCalendar()->timeZone();
        event->setDtStart(m_variables->getStartDateTime().toTimeZone(timeZone));
        event->setDtEnd(m_variables->getEndDateTime().toTimeZone(timeZone));
        event->setSummary(m_variables->getSummary());
        event->setAllDay(m_variables->getFloating());
        event->setDescription(m_variables->getDescription());
        event->setLocation(m_variables->getLocation());

        Akonadi::CalendarBase::Ptr const calendar = m_variables->getCalendar();
        QEventLoop loop;
        QObject::connect(calendar.data(), &Akonadi::CalendarBase::createFinished, &loop, &QEventLoop::quit);
        QElapsedTimer t;
        t.start();
        Q_ASSERT(calendar->incidence(event->uid()) == nullptr); // can't exist yet
        if (!m_variables->allowGui()) {
            Akonadi::IncidenceChanger *changer = calendar->incidenceChanger();
            changer->setShowDialogsOnError(false);
            Akonadi::Collection const collection = m_variables->collectionId() != -1
                ? Akonadi::Collection(m_variables->collectionId())
                : Akonadi::Collection(CalendarSupport::KCalPrefs::instance()->defaultEventCalendarId());

            if (!collection.isValid()) {
                cout << i18n("Calendar is invalid. Please specify one with --calendar").toLocal8Bit().data() << "\n";
            }

            changer->setDefaultCollection(collection);
            changer->setDestinationPolicy(Akonadi::IncidenceChanger::DestinationPolicyNeverAsk);
        }
        calendar->addEvent(event);
        loop.exec();
        status = calendar->incidence(event->uid()) != nullptr;
        if (status) {
            cout << i18n("Success: \"%1\" inserted", m_variables->getSummary()).toLocal8Bit().data() << '\n';
        } else {
            cout << i18n("Failure: \"%1\" not inserted", m_variables->getSummary()).toLocal8Bit().data() << '\n';
            status = false;
        }
    }

    return status;
}

bool KonsoleKalendarAdd::addImportedCalendar()
{
    MemoryCalendar::Ptr const cal(new MemoryCalendar(QTimeZone::utc()));
    FileStorage instore(cal, m_variables->getImportFile());
    if (!instore.load()) {
        return false;
    }
    Akonadi::CalendarBase::Ptr const calendar = m_variables->getCalendar();

    if (!m_variables->allowGui()) {
        Akonadi::IncidenceChanger *changer = calendar->incidenceChanger();
        changer->setShowDialogsOnError(false);
        Akonadi::Collection const collection = m_variables->collectionId() != -1
            ? Akonadi::Collection(m_variables->collectionId())
            : Akonadi::Collection(CalendarSupport::KCalPrefs::instance()->defaultEventCalendarId());

        if (!collection.isValid()) {
            cout << i18n("Calendar is invalid. Please specify one with --calendar").toLocal8Bit().data() << "\n";
        }

        changer->setDefaultCollection(collection);
        changer->setDestinationPolicy(Akonadi::IncidenceChanger::DestinationPolicyNeverAsk);
    }

    QEventLoop loop;
    QObject::connect(calendar.data(), &Akonadi::CalendarBase::createFinished, &loop, &QEventLoop::quit);
    QElapsedTimer t;
    const auto rawEvents = cal->rawEvents();
    for (const auto &event : rawEvents) {
        if (calendar->incidence(event->uid()) != nullptr) {
            if (m_variables->isVerbose()) {
                cout << i18n("Insert Event skipped, because UID \"%1\" is already known.", event->uid()).toLocal8Bit().data() << '\n';
            } else {
                qCInfo(KONSOLEKALENDAR_LOG) << "Event with UID " << event->uid() << "is already in calendar, skipping import of this Event.";
            }
            continue;
        }
        if (m_variables->isVerbose()) {
            cout << i18n("Add Event with UID \"%1\".", event->uid()).toLocal8Bit().data() << '\n';
        }
        if (m_variables->isDryRun()) {
            continue;
        }
        t.start();
        calendar->addEvent(event);
        loop.exec();
        if (calendar->incidence(event->uid()) == nullptr) {
            return false;
        }
    }
    return true;
}

void KonsoleKalendarAdd::printSpecs()
{
    cout << i18n("  What:  %1", m_variables->getSummary()).toLocal8Bit().data() << '\n';

    cout << i18n("  Begin: %1", m_variables->getStartDateTime().toString(Qt::TextDate)).toLocal8Bit().data() << '\n';

    cout << i18n("  End:   %1", m_variables->getEndDateTime().toString(Qt::TextDate)).toLocal8Bit().data() << '\n';

    if (m_variables->getFloating() == true) {
        cout << i18n("  No Time Associated with Event").toLocal8Bit().data() << '\n';
    }

    cout << i18n("  Desc:  %1", m_variables->getDescription()).toLocal8Bit().data() << '\n';

    cout << i18n("  Location:  %1", m_variables->getLocation()).toLocal8Bit().data() << '\n';
}
