/*
 * 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 "mainwindowtabbar.h"
#include "src/configuration.h"
#include "src/mainwindow/mainwindow.h"
#include <QContextMenuEvent>
#include <QShortcut>
#include <QMenu>

MainWindowTabBar::MainWindowTabBar(const std::shared_ptr<Configuration> &config, MainWindow *parent)
    : QTabBar(parent)
{
    Q_CHECK_PTR(parent);
    m_parent = parent;

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

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

    QShortcut *tabCloseShortcut = new QShortcut(parent);
    tabCloseShortcut->setKey(QKeySequence(QString::fromStdString(config->value<std::string>("browser.shortcuts.tabClose").value())));
    connect(tabCloseShortcut, &QShortcut::activated, [this]() {
        this->removeTab(currentIndex());
    });

    QShortcut *tabLeftShortcut = new QShortcut(parent);
    tabLeftShortcut->setKey(QKeySequence(QString::fromStdString(config->value<std::string>("browser.shortcuts.tabLeft").value())));
    connect(tabLeftShortcut, &QShortcut::activated, [this]() {
        this->setCurrentIndex(currentIndex() - 1);
    });

    QShortcut *tabRightShortcut = new QShortcut(parent);
    tabRightShortcut->setKey(QKeySequence(QString::fromStdString(config->value<std::string>("browser.shortcuts.tabRight").value())));
    connect(tabRightShortcut, &QShortcut::activated, [this]() {
        this->setCurrentIndex(currentIndex() + 1);
    });
}

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

int MainWindowTabBar::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);
    });
    connect(view, &QWebEngineView::iconChanged, [this, view](const QIcon &icon) {
        int index = m_views.indexOf(view);
        setTabIcon(index, icon);
    });

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

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

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

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

void MainWindowTabBar::contextMenuEvent(QContextMenuEvent *event)
{
    int tabIndex = tabAt(event->pos());
    if(tabIndex < 0) {
        return;
    }

    QMenu menu(this);
    QAction *closeAction = menu.addAction(tr("Close tab"));
    connect(closeAction, &QAction::triggered, this, [tabIndex, this]() {
        removeTab(tabIndex);
    });
    menu.exec(event->globalPos());
}

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

void MainWindowTabBar::handleCurrentChanged(int index)
{
    if(index < 0) {
        addTab(createWebView(m_parent->profile()->homepage(), m_parent->profile(), m_parent));
        return;
    }

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

void MainWindowTabBar::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 MainWindowTabBar::updateTabText(WebView *view, const QString &text)
{
    int index = m_views.indexOf(view);
    setTabText(index, text);
}

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

WebView *createWebView(const QUrl &url, WebEngineProfile *profile, MainWindow *parent)
{
    WebView *view = new WebView(parent);
    WebPage *page = new WebPage(profile);
    view->setPage(page);
    page->load(url);

    return view;
}