/***************************************************************************
 *   Copyright (C) 2005-2022 by the Quassel Project                        *
 *   devel@quassel-irc.org                                                 *
 *                                                                         *
 *   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) version 3.                                           *
 *                                                                         *
 *   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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "nicklistwidget.h"

#include <QAbstractButton>
#include <QAction>
#include <QDebug>
#include <QEvent>

#include "buffermodel.h"
#include "client.h"
#include "networkmodel.h"
#include "nickview.h"
#include "nickviewfilter.h"
#include "qtuisettings.h"

NickListWidget::NickListWidget(QWidget* parent)
    : AbstractItemView(parent)
{
    ui.setupUi(this);
}

QDockWidget* NickListWidget::dock() const
{
    auto* dock = qobject_cast<QDockWidget*>(parent());
    if (dock)
        return dock;
    else
        return nullptr;
}

void NickListWidget::hideEvent(QHideEvent* event)
{
    emit nickSelectionChanged(QModelIndexList());
    AbstractItemView::hideEvent(event);
}

void NickListWidget::showEvent(QShowEvent* event)
{
    auto* view = qobject_cast<NickView*>(ui.stackedWidget->currentWidget());
    if (view)
        emit nickSelectionChanged(view->selectedIndexes());

    AbstractItemView::showEvent(event);
}

void NickListWidget::showWidget(bool visible)
{
    if (!selectionModel())
        return;

    QModelIndex currentIndex = selectionModel()->currentIndex();
    if (currentIndex.data(NetworkModel::BufferTypeRole) == BufferInfo::ChannelBuffer) {
        QDockWidget* dock_ = dock();
        if (!dock_)
            return;

        if (visible)
            dock_->show();
        else
            dock_->close();
    }
}

void NickListWidget::setVisible(bool visible)
{
    QWidget::setVisible(visible);
    QDockWidget* dock_ = dock();
    if (!dock_)
        return;

    if (visible)
        dock_->show();
    else
        dock_->close();
}

void NickListWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous)
{
    BufferInfo::Type bufferType = (BufferInfo::Type)current.data(NetworkModel::BufferTypeRole).toInt();
    BufferId newBufferId = current.data(NetworkModel::BufferIdRole).value<BufferId>();
    BufferId oldBufferId = previous.data(NetworkModel::BufferIdRole).value<BufferId>();

    if (bufferType != BufferInfo::ChannelBuffer) {
        ui.stackedWidget->setCurrentWidget(ui.emptyPage);
        emit nickSelectionChanged(QModelIndexList());
        return;
    }

    // See NickListDock::NickListDock() below
    //   if(bufferType != BufferInfo::ChannelBuffer) {
    //     ui.stackedWidget->setCurrentWidget(ui.emptyPage);
    //     QDockWidget *dock_ = dock();
    //     if(dock_) {
    //       dock_->close();
    //     }
    //     return;
    //   } else {
    //     QDockWidget *dock_ = dock();
    //     if(dock_ && dock_->toggleViewAction()->isChecked()) {
    //       dock_->show();
    //     }
    //   }

    if (newBufferId == oldBufferId)
        return;

    NickView* view;
    if (nickViews.contains(newBufferId)) {
        view = nickViews.value(newBufferId);
        ui.stackedWidget->setCurrentWidget(view);
    }
    else {
        view = new NickView(this);
        auto* filter = new NickViewFilter(newBufferId, Client::networkModel());
        view->setModel(filter);
        QModelIndex source_current = Client::bufferModel()->mapToSource(current);
        view->setRootIndex(filter->mapFromSource(source_current));
        nickViews[newBufferId] = view;
        ui.stackedWidget->addWidget(view);
        ui.stackedWidget->setCurrentWidget(view);
        connect(view, &NickView::selectionUpdated, this, &NickListWidget::onNickSelectionChanged);
    }
    emit nickSelectionChanged(view->selectedIndexes());
}

void NickListWidget::onNickSelectionChanged()
{
    auto* view = qobject_cast<NickView*>(sender());
    Q_ASSERT(view);
    if (view != ui.stackedWidget->currentWidget()) {
        qDebug() << "Nick selection of hidden view changed!";
        return;
    }
    emit nickSelectionChanged(view->selectedIndexes());
}

void NickListWidget::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
{
    Q_ASSERT(model());
    if (!parent.isValid()) {
        // ok this means that whole networks are about to be removed
        // we can't determine which buffers are affect, so we hope that all nets are removed
        // this is the most common case (for example disconnecting from the core or terminating the clint)
        NickView* nickView;
        QHash<BufferId, NickView*>::iterator iter = nickViews.begin();
        while (iter != nickViews.end()) {
            nickView = *iter;
            iter = nickViews.erase(iter);
            ui.stackedWidget->removeWidget(nickView);
            QAbstractItemModel* model = nickView->model();
            nickView->setModel(nullptr);
            if (auto* filter = qobject_cast<QSortFilterProxyModel*>(model))
                filter->setSourceModel(nullptr);
            model->deleteLater();
            nickView->deleteLater();
        }
    }
    else {
        // check if there are explicitly buffers removed
        // Make sure model is valid first
        if (!parent.model()) {
            return;
        }
        for (int i = start; i <= end; i++) {
            QVariant variant = parent.model()->index(i, 0, parent).data(NetworkModel::BufferIdRole);
            if (!variant.isValid())
                continue;

            BufferId bufferId = variant.value<BufferId>();
            removeBuffer(bufferId);
        }
    }
}

void NickListWidget::removeBuffer(BufferId bufferId)
{
    if (!nickViews.contains(bufferId))
        return;

    NickView* view = nickViews.take(bufferId);
    ui.stackedWidget->removeWidget(view);
    QAbstractItemModel* model = view->model();
    view->setModel(nullptr);
    if (auto* filter = qobject_cast<QSortFilterProxyModel*>(model))
        filter->setSourceModel(nullptr);
    model->deleteLater();
    view->deleteLater();
}

QSize NickListWidget::sizeHint() const
{
    QWidget* currentWidget = ui.stackedWidget->currentWidget();
    if (!currentWidget || currentWidget == ui.emptyPage)
        return {100, height()};
    else
        return currentWidget->sizeHint();
}

// ==============================
//  NickList Dock
// ==============================
NickListDock::NickListDock(const QString& title, QWidget* parent)
    : QDockWidget(title, parent)
{
    // THIS STUFF IS NEEDED FOR NICKLIST AUTOHIDE...
    // AS THIS BRINGS LOTS OF FUCKUPS WITH IT IT'S DEACTIVATED FOR NOW...

    //   QAction *toggleView = toggleViewAction();
    //   disconnect(toggleView, SIGNAL(triggered(bool)), this, 0);
    //   toggleView->setChecked(QtUiSettings().value("ShowNickList", QVariant(true)).toBool());

    //   // reconnecting the closebuttons clicked signal to the action
    //   foreach(QAbstractButton *button, findChildren<QAbstractButton *>()) {
    //     if(disconnect(button, SIGNAL(clicked()), this, SLOT(close())))
    //       connect(button, SIGNAL(clicked()), toggleView, SLOT(trigger()));
    //   }
}

void NickListDock::setLocked(bool locked)
{
    if (locked) {
        setFeatures({});
    }
    else {
        setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
    }
}

// NickListDock::~NickListDock() {
//   QtUiSettings().setValue("ShowNickList", toggleViewAction()->isChecked());
// }

// bool NickListDock::event(QEvent *event) {
//   switch (event->type()) {
//   case QEvent::Hide:
//   case QEvent::Show:
//     emit visibilityChanged(event->type() == QEvent::Show);
//     return QWidget::event(event);
//   default:
//     return QDockWidget::event(event);
//   }
// }
