/*
 * 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/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "urllineedit.h"
#include <QMenu>
#include <QShortcut>
#include <QApplication>
#include <QClipboard>
#include "../addressbar.h"

UrlLineEdit::UrlLineEdit(QWidget *parent)
    : QLineEdit(parent)
    , m_listView(new Completer(this))
{
    setObjectName("UrlBar");
    setPlaceholderText(tr("Enter address"));

    m_listView->setVisible(false);
    connect(m_listView, &Completer::completionActivated, this, &UrlLineEdit::setText);

    addressbar = qobject_cast<AddressBar *>(parent);
    Q_CHECK_PTR(addressbar);

    auto *copyAction = new QAction(tr("Copy URL"), this);
    connect(copyAction, &QAction::triggered, this, [this]() {
        qApp->clipboard()->setText(this->text());
    });
    actions.append(copyAction);

    auto *pasteAction = new QAction(tr("Paste URL"), this);
    connect(pasteAction, &QAction::triggered, this, [this]() {
        this->setText(qApp->clipboard()->text());
        this->setFocus();
    });
    actions.append(pasteAction);

    auto *loadAction = new QAction(tr("Paste and load"), this);
    connect(loadAction, &QAction::triggered, this, [this]() {
        emit addressbar->load(QUrl::fromUserInput(qApp->clipboard()->text()));
        clearFocus();
    });
    actions.append(loadAction);

    auto *searchAction = new QAction(tr("Paste and search"), this);
    connect(searchAction, &QAction::triggered, this, [this]() {
        emit addressbar->search(qApp->clipboard()->text());
        clearFocus();
    });
    actions.append(searchAction);

    menuAction = addAction(style()->standardIcon(QStyle::SP_DriveNetIcon), QLineEdit::LeadingPosition);
    connect(menuAction, &QAction::triggered, this, [this]() {
        auto *menu = new QMenu();
        menu->setAttribute(Qt::WA_DeleteOnClose, true);
        menu->setMinimumWidth(240);
        menu->addActions(actions);

        menu->exec(this->mapToGlobal(QPoint(0, height())));
    });

    auto *goAction = addAction(style()->standardIcon(QStyle::SP_DialogOkButton), QLineEdit::TrailingPosition);
    connect(goAction, &QAction::triggered, this, [this]() {
        emit returnPressed();
    });

    QTextCharFormat hostnameFormat;
    hostnameFormat.setFontWeight(QFont::Bold);
    m_hostFormat.format = hostnameFormat;
}

void UrlLineEdit::setUrl(const QUrl &url)
{
    QString urlText = url.toString();
    QString domain = url.host();

    m_hostFormat.start = urlText.indexOf(domain);
    m_hostFormat.length = domain.length();

    clear();
    clearTextFormat();
    setTextFormat(m_hostFormat);
    setText(urlText);
}

void UrlLineEdit::updateCompleter(const QStringList &l)
{
    if(!m_listView->updateItems(l)) {
        m_listView->hide();
        return;
    }

    // positioning
    m_listView->setFixedWidth(width());
    m_listView->move(mapToGlobal(QPoint(0, height())));
    m_listView->show();
}

void UrlLineEdit::focusInEvent(QFocusEvent *event)
{
    // a context menu event also causes a focusInEvent, so if text is selected
    // skip the formatting step
    if(event->reason() == Qt::PopupFocusReason) {
        QLineEdit::focusInEvent(event);
        return;
    }

    clearTextFormat();
    QLineEdit::focusInEvent(event);
}

void UrlLineEdit::focusOutEvent(QFocusEvent *event)
{
    // a context menu event causes a focusOutEvent, and setUrl will clear the
    // selection, and this would prevent the menu from working properly
    if(event->reason() == Qt::PopupFocusReason) {
        QLineEdit::focusOutEvent(event);
        return;
    }

    const QUrl url = QUrl::fromUserInput(text());
    if(url.isValid())
        setUrl(url);

    emit addressbar->giveFocus();
    QLineEdit::focusOutEvent(event);
}

void UrlLineEdit::keyPressEvent(QKeyEvent *event)
{
    if(m_listView->keyPressed(event)) {
        event->accept();
        return;
    } else if(event->key() == Qt::Key::Key_Escape) {
        clearFocus();
        event->accept();
        return;
    }

    QLineEdit::keyPressEvent(event);
}

// formatting taken from: https://forum.qt.io/topic/60962/setting-qlineedit-text-bold
void UrlLineEdit::setTextFormat(const QTextLayout::FormatRange &format)
{
    QList<QInputMethodEvent::Attribute> attributes;
    attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, format.start, format.length, format.format));
    QInputMethodEvent ev(QString(), attributes);
    event(&ev);
}

void UrlLineEdit::clearTextFormat()
{
    setTextFormat(QTextLayout::FormatRange());
}