/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/smolbote.hg
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "tabbar.h"
#include "mainwindow/mainwindow.h"
#include "webengine/webengineprofile.h"
#include "webengine/webview.h"
#include <QContextMenuEvent>
#include <QMenu>

TabBar::TabBar(const QHash<QString, QString> &config, MainWindow *parent)
    : QTabBar(parent)
{
    Q_CHECK_PTR(parent);

    setElideMode(Qt::ElideRight);
    setTabsClosable(true);
    setMovable(true);
    setContextMenuPolicy(Qt::DefaultContextMenu);

    connect(this, &TabBar::tabCloseRequested, this, &TabBar::removeTab);
    connect(this, &TabBar::currentChanged, this, &TabBar::handleCurrentChanged);
    connect(this, &TabBar::tabMoved, this, &TabBar::updateVectorArrangement);

    newTab_action = new QAction(tr("New Tab"), parent);
    newTab_action->setObjectName("newTab_action");
    newTab_action->setShortcut(QKeySequence(config["tabbar.shortcuts.new"]));
    connect(newTab_action, &QAction::triggered, parent, [parent, this]() {
        parent->newTab(parent->profile()->newtab());
    });
    parent->addAction(newTab_action);

    closeTab_action = new QAction(tr("Close Tab"), parent);
    closeTab_action->setObjectName("closeTab_action");
    closeTab_action->setShortcut(QKeySequence(config["tabbar.shortcuts.close"]));
    connect(closeTab_action, &QAction::triggered, this, [this]() {
        removeTab(currentIndex());
    });
    parent->addAction(closeTab_action);

    leftTab_action = new QAction(tr("Left Tab"), parent);
    leftTab_action->setObjectName("leftTab_action");
    leftTab_action->setShortcut(QKeySequence(config["tabbar.shortcuts.left"]));
    connect(leftTab_action, &QAction::triggered, this, [this]() {
        setCurrentIndex(currentIndex() - 1);
    });
    parent->addAction(leftTab_action);

    rightTab_action = new QAction(tr("Right Tab"), parent);
    rightTab_action->setObjectName("rightTab_action");
    rightTab_action->setShortcut(QKeySequence(config["tabbar.shortcuts.right"]));
    connect(rightTab_action, &QAction::triggered, this, [this]() {
        setCurrentIndex(currentIndex() + 1);
    });
    parent->addAction(rightTab_action);

    // tab context menu
    {
        tabContextMenu = new QMenu(this);

        auto *closeTab = tabContextMenu->addAction(tr("Close Tab"));
        connect(closeTab, &QAction::triggered, this, [this]() {
            removeTab(tabAt(mapFromGlobal(tabContextMenu->pos())));
        });

        auto *closeTabsLeft = tabContextMenu->addAction(tr("Close Tabs left"));
        connect(closeTabsLeft, &QAction::triggered, this, [this]() {
            int idx = tabAt(mapFromGlobal(tabContextMenu->pos()));
            for(int i = idx - 1; i >= 0; --i) {
                removeTab(i);
            }
        });

        auto *closeTabsRight = tabContextMenu->addAction(tr("Close Tabs right"));
        connect(closeTabsRight, &QAction::triggered, this, [this]() {
            int idx = tabAt(mapFromGlobal(tabContextMenu->pos()));
            for(int i = count() - 1; i > idx; --i) {
                removeTab(i);
            }
        });
    }
}

TabBar::~TabBar()
{
    // cleanup
    qDeleteAll(m_views);
    m_views.clear();
}

void TabBar::setProfile(WebEngineProfile *profile)
{
    Q_CHECK_PTR(profile);

    for(auto view : qAsConst(m_views)) {
        auto *page = new WebPage(profile);
        page->load(view->url());
        view->page()->deleteLater();
        view->setPage(page);
    }
}

WebView *TabBar::currentView()
{
    return m_views.at(currentIndex());
}

int TabBar::addTab(WebView *view)
{
    m_views.append(view);

    connect(view, &QWebEngineView::titleChanged, [this, view](const QString &title) {
        int index = m_views.indexOf(view);
        setTabText(index, title);
        setTabToolTip(index, title);
    });
    connect(view, &QWebEngineView::iconChanged, [this, view](const QIcon &icon) {
        int index = m_views.indexOf(view);
        setTabIcon(index, icon);
    });

    return QTabBar::addTab("New Tab");
}

void TabBar::removeTab(int index)
{
    // remove the tab data from the index
    m_views.at(index)->deleteLater();
    m_views.remove(index);

    // remove the tab from the QTabBar
    // this emits the currentTabChanged signal, so it should be done after the view is removed from the index
    QTabBar::removeTab(index);
}

void TabBar::contextMenuEvent(QContextMenuEvent *event)
{
    // check if the context menu was called on a tab
    int tabIndex = tabAt(event->pos());
    if(tabIndex < 0) {
        return;
    }

    tabContextMenu->exec(event->globalPos());
}

QSize TabBar::tabSizeHint(int index) const
{
    Q_UNUSED(index)
    return QSize(200, this->height());
}

void TabBar::handleCurrentChanged(int index)
{
    if(index < 0) {
        newTab_action->trigger();
        return;
    }

    emit currentTabChanged(m_views.at(index));
}

void TabBar::updateVectorArrangement(int from, int to)
{
    m_views.move(from, to);
}