/*
   SPDX-FileCopyrightText: 2025-2026 Laurent Montel <montel@kde.org>

   SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include "richtextquicktextformat.h"

#include <KLocalizedString>

#include <KSeparator>
#include <QEvent>
#include <QHBoxLayout>
#include <QTextEdit>
#include <QTimer>
#include <QToolButton>

#include <chrono>
using namespace std::chrono_literals;

using namespace Qt::Literals::StringLiterals;
using namespace TextAddonsWidgets;
RichTextQuickTextFormat::RichTextQuickTextFormat(QTextEdit *editor, QWidget *parent)
    : QFrame(parent)
    , mEditor(editor)
    , mUpdatePositionTimer(new QTimer(this))
    , mMainLayout(new QHBoxLayout(this))
{
    mMainLayout->setObjectName(u"mMainLayout"_s);
    mMainLayout->setContentsMargins({});
    mMainLayout->setSpacing(0);
    setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);

    if (mEditor) {
        connect(mEditor, &QTextEdit::selectionChanged, this, &RichTextQuickTextFormat::slotSelectionChanged);
        mUpdatePositionTimer->setInterval(20ms);
        mUpdatePositionTimer->setSingleShot(true);
        connect(mUpdatePositionTimer, &QTimer::timeout, this, &RichTextQuickTextFormat::updatePosition);
        mEditor->viewport()->installEventFilter(this);
    }
}

RichTextQuickTextFormat::~RichTextQuickTextFormat() = default;

RichTextQuickTextFormat::QuickTextFormatTypes RichTextQuickTextFormat::formatTypes() const
{
    return mFormatTypes;
}

void RichTextQuickTextFormat::setFormatTypes(QuickTextFormatTypes newFormatTypes)
{
    if (mFormatTypes != newFormatTypes) {
        mFormatTypes = newFormatTypes;
        updateActions();
    }
}

void RichTextQuickTextFormat::updateActions()
{
    if (mFormatTypes & QuickTextFormatType::Bold) {
        auto boldButton = new QToolButton(this);
        boldButton->setFocusPolicy(Qt::NoFocus);
        boldButton->setObjectName(u"boldButton"_s);
        boldButton->setIconSize(QSize(12, 12));
        boldButton->setIcon(QIcon::fromTheme(u"format-text-bold"_s));
        boldButton->setAutoRaise(true);
        boldButton->setToolTip(i18nc("@info:tooltip", "Bold"));
        connect(boldButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::Bold);
        });
        mMainLayout->addWidget(boldButton);
    }

    if (mFormatTypes & QuickTextFormatType::Italic) {
        auto italicButton = new QToolButton(this);
        italicButton->setObjectName(u"italicButton"_s);
        italicButton->setFocusPolicy(Qt::NoFocus);
        italicButton->setIconSize(QSize(12, 12));
        italicButton->setIcon(QIcon::fromTheme(u"format-text-italic"_s));
        italicButton->setAutoRaise(true);
        italicButton->setToolTip(i18nc("@info:tooltip", "Italic"));
        connect(italicButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::Italic);
        });
        mMainLayout->addWidget(italicButton);
    }

    if (mFormatTypes & QuickTextFormatType::StrikeThrough) {
        auto strikeThroughButton = new QToolButton(this);
        strikeThroughButton->setObjectName(u"strikeThroughButton"_s);
        strikeThroughButton->setFocusPolicy(Qt::NoFocus);
        strikeThroughButton->setIconSize(QSize(12, 12));
        strikeThroughButton->setIcon(QIcon::fromTheme(u"format-text-strikethrough"_s));
        strikeThroughButton->setAutoRaise(true);
        strikeThroughButton->setToolTip(i18nc("@info:tooltip", "Strike Through"));
        connect(strikeThroughButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::StrikeThrough);
        });
        mMainLayout->addWidget(strikeThroughButton);
    }

    if (mFormatTypes & QuickTextFormatType::UnderLine) {
        auto underlineButton = new QToolButton(this);
        underlineButton->setObjectName(u"underlineButton"_s);
        underlineButton->setFocusPolicy(Qt::NoFocus);
        underlineButton->setIconSize(QSize(12, 12));
        underlineButton->setIcon(QIcon::fromTheme(u"format-text-underline"_s));
        underlineButton->setAutoRaise(true);
        underlineButton->setToolTip(i18nc("@info:tooltip", "Underline"));
        connect(underlineButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::UnderLine);
        });
        mMainLayout->addWidget(underlineButton);
    }

    mMainLayout->addWidget(new KSeparator(Qt::Vertical, this));

    if (mFormatTypes & QuickTextFormatType::CodeBlock) {
        auto codeBlockButton = new QToolButton(this);
        codeBlockButton->setObjectName(u"codeBlockButton"_s);
        codeBlockButton->setFocusPolicy(Qt::NoFocus);
        codeBlockButton->setIconSize(QSize(12, 12));
        codeBlockButton->setIcon(QIcon::fromTheme(u"format-text-code"_s));
        codeBlockButton->setToolTip(i18nc("@info:tooltip", "Code Block"));
        codeBlockButton->setAutoRaise(true);
        connect(codeBlockButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::CodeBlock);
        });

        mMainLayout->addWidget(codeBlockButton);
    }

    if (mFormatTypes & QuickTextFormatType::BlockQuote) {
        auto blockQuoteButton = new QToolButton(this);
        blockQuoteButton->setObjectName(u"blockQuoteButton"_s);
        blockQuoteButton->setFocusPolicy(Qt::NoFocus);
        blockQuoteButton->setIconSize(QSize(12, 12));
        blockQuoteButton->setIcon(QIcon::fromTheme(u"format-text-blockquote"_s));
        blockQuoteButton->setToolTip(i18nc("@info:tooltip", "Quote Text"));
        blockQuoteButton->setAutoRaise(true);
        connect(blockQuoteButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::BlockQuote);
        });

        mMainLayout->addWidget(blockQuoteButton);
    }

    mMainLayout->addWidget(new KSeparator(Qt::Vertical, this));

    if (mFormatTypes & QuickTextFormatType::InsertLink) {
        auto insertLinkButton = new QToolButton(this);
        insertLinkButton->setObjectName(u"insertLinkButton"_s);
        insertLinkButton->setFocusPolicy(Qt::NoFocus);
        insertLinkButton->setIconSize(QSize(12, 12));
        insertLinkButton->setIcon(QIcon::fromTheme(u"link"_s));
        insertLinkButton->setToolTip(i18nc("@info:tooltip", "Insert Link"));
        insertLinkButton->setAutoRaise(true);
        connect(insertLinkButton, &QToolButton::clicked, this, [this]() {
            Q_EMIT quickTextFormatRequested(RichTextQuickTextFormat::QuickTextFormatType::InsertLink);
        });
        mMainLayout->addWidget(insertLinkButton);
    }
}

void RichTextQuickTextFormat::updatePosition()
{
    if (!isEnabled()) {
        return;
    }
    if (mEditor->textCursor().hasSelection()) {
        const QRect cursorRect = mEditor->cursorRect();
        const QPoint globalPos = mEditor->viewport()->mapToGlobal(cursorRect.topLeft());
        move(globalPos.x(), globalPos.y() - height());
        show();
    } else {
        hide();
    }
}

void RichTextQuickTextFormat::slotSelectionChanged()
{
    if (!isEnabled()) {
        return;
    }
    if (!mEditor->textCursor().hasSelection()) {
        hide();
    }
}

bool RichTextQuickTextFormat::eventFilter(QObject *watched, QEvent *event)
{
    if (isEnabled()) {
        if (watched == mEditor->viewport()) {
            if (event->type() == QEvent::Move || event->type() == QEvent::Resize) {
                if (isVisible()) {
                    if (mUpdatePositionTimer->isActive()) {
                        mUpdatePositionTimer->stop();
                    }
                    mUpdatePositionTimer->start();
                }
            } else if (event->type() == QEvent::WindowDeactivate) {
                if (isVisible()) {
                    if (mUpdatePositionTimer->isActive()) {
                        mUpdatePositionTimer->stop();
                    }
                    hide();
                }
            } else if (event->type() == QEvent::MouseButtonRelease) {
                if (!isVisible()) {
                    if (mEditor->textCursor().hasSelection()) {
                        updatePosition();
                    }
                } else {
                    if (!mEditor->textCursor().hasSelection()) {
                        if (mUpdatePositionTimer->isActive()) {
                            mUpdatePositionTimer->stop();
                        }
                        hide();
                    }
                }
            }
        }
    }
    return QFrame::eventFilter(watched, event);
}

#include "moc_richtextquicktextformat.cpp"
