/*
    SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com>
    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <QAction>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QToolButton>

#include <KMainWindow>
#include <KMessageBox>

#include "feedlist.h"
#include "feedlistview.h"
#include "feedretriever.h"
#include "feedwidget.h"
#include "filter.h"
#include "filtereditor.h"
#include "filterlist.h"
#include "filterlistview.h"
#include "ktfeed.h"
#include "linkdownloader.h"
#include "managefiltersdlg.h"
#include "syndicationactivity.h"
#include "syndicationplugin.h"
#include "syndicationtab.h"
#include <interfaces/coreinterface.h>
#include <interfaces/functions.h>
#include <interfaces/guiinterface.h>
#include <magnet/magnetlink.h>
#include <syndication/loader.h>
#include <util/error.h>
#include <util/fileops.h>

namespace kt
{
SyndicationActivity::SyndicationActivity(SyndicationPlugin *sp, QWidget *parent)
    : Activity(i18n("Syndication"), QStringLiteral("application-rss+xml"), 30, parent)
    , sp(sp)
{
    QString ddir = kt::DataDir() + QStringLiteral("syndication/");
    if (!bt::Exists(ddir))
        bt::MakeDir(ddir, true);

    setToolTip(i18n("Manages RSS and Atom feeds"));
    QHBoxLayout *layout = new QHBoxLayout(this);
    splitter = new QSplitter(Qt::Horizontal, this);
    layout->addWidget(splitter);

    feed_list = new FeedList(ddir, this);
    filter_list = new FilterList(this);
    tab = new SyndicationTab(sp->actionCollection(), feed_list, filter_list, splitter);
    splitter->addWidget(tab);

    feed_widget = new FeedWidget(filter_list, this, splitter);
    splitter->addWidget(feed_widget);
    splitter->setStretchFactor(0, 1);
    splitter->setStretchFactor(1, 3);

    connect(tab->feedView(), &kt::FeedListView::feedActivated, this, &SyndicationActivity::showFeed);
    connect(tab->feedView(), &kt::FeedListView::enableRemove, sp->remove_feed, &QAction::setEnabled);
    connect(tab->feedView(), &kt::FeedListView::enableRemove, sp->manage_filters, &QAction::setEnabled);
    connect(tab->filterView(), &kt::FilterListView::filterActivated, this, qOverload<Filter *>(&SyndicationActivity::editFilter));
    connect(tab->filterView(), &kt::FilterListView::enableRemove, sp->remove_filter, &QAction::setEnabled);
    connect(tab->filterView(), &kt::FilterListView::enableEdit, sp->edit_filter, &QAction::setEnabled);

    filter_list->loadFilters(kt::DataDir() + QStringLiteral("syndication/filters"));
    feed_list->loadFeeds(filter_list, this);
    feed_list->importOldFeeds();
}

SyndicationActivity::~SyndicationActivity()
{
}

void SyndicationActivity::loadState(KSharedConfigPtr cfg)
{
    KConfigGroup g = cfg->group(QStringLiteral("SyndicationActivity"));
    QString current = g.readEntry("current_feed", QString());

    Feed *f = feed_list->feedForDirectory(current);
    if (f)
        feed_widget->setFeed(f);

    QByteArray state = g.readEntry("splitter", QByteArray());
    splitter->restoreState(state);
    tab->loadState(g);
    feed_widget->loadState(g);
}

void SyndicationActivity::saveState(KSharedConfigPtr cfg)
{
    Feed *feed = feed_widget->getFeed();

    KConfigGroup g = cfg->group(QStringLiteral("SyndicationActivity"));
    g.writeEntry("current_feed", feed ? feed->directory() : QString());
    g.writeEntry("splitter", splitter->saveState());
    tab->saveState(g);
    feed_widget->saveState(g);
    g.sync();
}

void SyndicationActivity::addFeed()
{
    bool ok = false;
    QString url = QInputDialog::getText(sp->getGUI()->getMainWindow(),
                                        i18n("Enter the URL"),
                                        i18n("Please enter the URL of the RSS or Atom feed."),
                                        QLineEdit::Normal,
                                        QString(),
                                        &ok);
    if (!ok || url.isEmpty())
        return;

    Syndication::Loader *loader = Syndication::Loader::create(this, SLOT(loadingComplete(Syndication::Loader *, Syndication::FeedPtr, Syndication::ErrorCode)));
    QStringList sl = url.split(QStringLiteral(":COOKIE:"));
    if (sl.size() == 2) {
        FeedRetriever *retr = new FeedRetriever();
        retr->setAuthenticationCookie(sl.last());
        loader->loadFrom(QUrl(sl.first()), retr);
        downloads.insert(loader, url);
    } else {
        loader->loadFrom(QUrl(url), new FeedRetriever());
        downloads.insert(loader, url);
    }
}

void SyndicationActivity::loadingComplete(Syndication::Loader *loader, Syndication::FeedPtr feed, Syndication::ErrorCode status)
{
    if (status != Syndication::Success) {
        QString error = SyndicationErrorString(status);
        KMessageBox::error(tab, i18n("Failed to load feed %1: %2", downloads[loader], error));
        downloads.remove(loader);
        return;
    }

    try {
        QString ddir = kt::DataDir() + QStringLiteral("syndication/");
        Feed *f = new Feed(downloads[loader], feed, Feed::newFeedDir(ddir));
        connect(f, &Feed::downloadLink, this, &SyndicationActivity::downloadLink);
        f->save();
        feed_list->addFeed(f);
        feed_widget->setFeed(f);
    } catch (bt::Error &err) {
        KMessageBox::error(tab, i18n("Failed to create directory for feed %1: %2", downloads[loader], err.toString()));
    }
    downloads.remove(loader);
}

void SyndicationActivity::removeFeed()
{
    const QModelIndexList idx = tab->feedView()->selectedFeeds();
    for (const QModelIndex &i : idx) {
        Feed *f = feed_list->feedForIndex(i);
        if (f && feed_widget->getFeed() == f) {
            feed_widget->setFeed(nullptr);
        }
    }
    feed_list->removeFeeds(idx);
}

void SyndicationActivity::showFeed(Feed *f)
{
    if (!f)
        return;

    feed_widget->setFeed(f);
}

void SyndicationActivity::downloadLink(const QUrl &url, const QString &group, const QString &location, const QString &move_on_completion, bool silently)
{
    if (url.scheme() == QStringLiteral("magnet")) {
        MagnetLinkLoadOptions options;
        options.silently = silently;
        options.group = group;
        options.location = location;
        options.move_on_completion = move_on_completion;
        sp->getCore()->load(bt::MagnetLink(url), options);
    } else {
        LinkDownloader *dlr = new LinkDownloader(url, sp->getCore(), !silently, group, location, move_on_completion);
        dlr->start();
    }
}

Filter *SyndicationActivity::addNewFilter()
{
    Filter *filter = new Filter(i18n("New Filter"));
    FilterEditor dlg(filter, filter_list, feed_list, sp->getCore(), sp->getGUI()->getMainWindow());
    dlg.setWindowTitle(i18n("Add New Filter"));
    if (dlg.exec() == QDialog::Accepted) {
        filter_list->addFilter(filter);
        filter_list->saveFilters(kt::DataDir() + QStringLiteral("syndication/filters"));
        return filter;
    } else {
        delete filter;
        return nullptr;
    }
}

void SyndicationActivity::addFilter()
{
    addNewFilter();
}

void SyndicationActivity::removeFilter()
{
    const QModelIndexList indexes = tab->filterView()->selectedFilters();
    QList<Filter *> to_remove;
    for (const QModelIndex &idx : indexes) {
        Filter *f = filter_list->filterForIndex(idx);
        if (f)
            to_remove.append(f);
    }

    for (Filter *f : std::as_const(to_remove)) {
        feed_list->filterRemoved(f);
        filter_list->removeFilter(f);
        delete f;
    }

    filter_list->saveFilters(kt::DataDir() + QStringLiteral("syndication/filters"));
}

void SyndicationActivity::editFilter()
{
    QModelIndexList idx = tab->filterView()->selectedFilters();
    if (idx.count() == 0)
        return;

    Filter *f = filter_list->filterForIndex(idx.front());
    if (f)
        editFilter(f);
}

void SyndicationActivity::editFilter(Filter *f)
{
    FilterEditor dlg(f, filter_list, feed_list, sp->getCore(), sp->getGUI()->getMainWindow());
    if (dlg.exec() == QDialog::Accepted) {
        filter_list->filterEdited(f);
        filter_list->saveFilters(kt::DataDir() + QStringLiteral("syndication/filters"));
        feed_list->filterEdited(f);
    }
}

void SyndicationActivity::manageFilters()
{
    QModelIndexList idx = tab->feedView()->selectedFeeds();
    if (idx.count() == 0)
        return;

    Feed *f = feed_list->feedForIndex(idx.front());
    if (!f)
        return;

    ManageFiltersDlg dlg(f, filter_list, this, tab);
    if (dlg.exec() == QDialog::Accepted) {
        f->save();
        f->runFilters();
    }
}

void SyndicationActivity::editFeedName()
{
    QModelIndexList idx = tab->feedView()->selectedFeeds();
    if (idx.count())
        tab->feedView()->edit(idx.front());
}
}

#include "moc_syndicationactivity.cpp"
