#include "wizardwrapper.h"
#include "wordwizard.h"
#include "dconfigmanager.h"
#include "dbwrapper.h"
#include "private/eaiexecutor.h"
#include "private/welcomedialog.h"
#include "private/wizarddpushbutton.h"
#include "esystemcontext.h"
#include <report/followalongpoint.h>
#include <report/eventlogutil.h>
#ifdef COMPILE_ON_V25
#include "ddeshellwayland.h"
#endif
#include <QHBoxLayout>
#include <QMenu>
#include <QGraphicsDropShadowEffect>
#include <QScreen>
#include <QDBusInterface>

#include <DStyle>
#include <DDialog>
#include <DPlatformWindowHandle>
#include <DFontSizeManager>

DGUI_USE_NAMESPACE
DWIDGET_USE_NAMESPACE
using namespace uos_ai;

WizardWrapper::WizardWrapper(QWidget *parent) : DBlurEffectWidget(parent)
{
    initUI();
    initConnect();
    initAnimation();
}

WizardWrapper &WizardWrapper::instance() {
    static WizardWrapper instance;
    return instance;
}

void WizardWrapper::initUI()
{
    this->setFixedSize(32, 32);
    this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
#ifdef COMPILE_ON_V20
    if (ESystemContext::isWayland())
        this->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);
#endif
    this->setAttribute(Qt::WA_AlwaysShowToolTips);
    this->setAttribute(Qt::WA_TranslucentBackground);
    DPlatformWindowHandle handle(this, this);
    handle.setWindowRadius(8);
    this->setObjectName("selectionwidget");
    installEventFilter(this);

    m_iconBtn = new DIconButton(this);
    m_iconBtn->setFixedSize(QSize(20, 20));
    m_iconBtn->setIcon(QIcon::fromTheme("uos-ai-assistant"));
    m_iconBtn->setIconSize(QSize(20, 20));
    m_iconBtn->installEventFilter(this);

    m_searchBtn = new WizardDPushButton(tr("Search"));
    m_searchBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_ai_search"));
    m_searchBtn->setIconSize(QSize(16, 16));
    //m_searchBtn->setFixedHeight(24);
    m_searchBtn->setFlat(true);
    DFontSizeManager::instance()->bind(m_searchBtn, DFontSizeManager::T7, QFont::Normal);
    m_searchBtn->installEventFilter(this);

    m_explainBtn = new WizardDPushButton(tr("Explain"));
    m_explainBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_explain"));
    m_explainBtn->setIconSize(QSize(16, 16));
    //m_explainBtn->setFixedHeight(24);
    m_explainBtn->setFlat(true);
    DFontSizeManager::instance()->bind(m_explainBtn, DFontSizeManager::T7, QFont::Normal);
    m_explainBtn->installEventFilter(this);

    m_summaryBtn = new WizardDPushButton(tr("Summary"));
    m_summaryBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_summarize"));
    m_summaryBtn->setIconSize(QSize(16, 16));
    //m_summaryBtn->setFixedHeight(24);
    m_summaryBtn->setFlat(true);
    DFontSizeManager::instance()->bind(m_summaryBtn, DFontSizeManager::T7, QFont::Normal);
    m_summaryBtn->installEventFilter(this);

    m_translationBtn = new WizardDPushButton(tr("Translate"));
    m_translationBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_translation"));
    m_translationBtn->setIconSize(QSize(16, 16));
    //m_translationBtn->setFixedHeight(24);
    m_translationBtn->setFlat(true);
    DFontSizeManager::instance()->bind(m_translationBtn, DFontSizeManager::T7, QFont::Normal);
    m_translationBtn->installEventFilter(this);

    m_lineSep = new DWidget(this);
    DPalette sepPalette = m_lineSep->palette();
    sepPalette.setColor(DPalette::Window, QColor(0, 0, 0, 25));
    m_lineSep->setFixedSize(2, 15);
    m_lineSep->setPalette(sepPalette);
    m_lineSep->setAutoFillBackground(true);

    m_lineSep1 = new DWidget(this);
    m_lineSep1->setFixedSize(2, 15);
    m_lineSep1->setPalette(sepPalette);
    m_lineSep1->setAutoFillBackground(true);

    m_lineSep2 = new DWidget(this);
    m_lineSep2->setFixedSize(2, 15);
    m_lineSep2->setPalette(sepPalette);
    m_lineSep2->setAutoFillBackground(true);

    m_lineSepSpace = new DWidget(this);
    m_lineSepSpace->setFixedSize(5, 15);

    m_moreBtn = new WizardDPushButton(this);
    m_moreBtn->setFlat(true);
    m_moreBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_more"));
    m_moreBtn->setIconSize(QSize(20, 20));
    m_moreBtn->setFixedHeight(24);
    m_moreBtn->installEventFilter(this);

    m_closeBtn = new WizardDPushButton(this);
    m_closeBtn->setFlat(true);
    m_closeBtn->setIcon(QIcon::fromTheme("uos-ai-assistant_close"));
    m_closeBtn->setIconSize(QSize(20, 20));
    m_closeBtn->setFixedHeight(24);
    m_closeBtn->installEventFilter(this);

    m_continueAction = new QAction(tr("Continue Writing"));
    m_expandAction = new QAction(tr("Expand"));
    m_correctAction = new QAction(tr("Correct"));
    m_hiddenAction = new QAction(tr("Hide"));

    m_polishmenu = new DMenu(tr("Retouch"));
    m_polishFormal = new QAction(tr("Formal and professional"));
    m_polishFriendly = new QAction(tr("Friendly"));
    m_polishHumor = new QAction(tr("Humorous"));
    m_polishPassionate = new QAction(tr("Inspirational"));
    m_polishmenu->addAction(m_polishFormal);
    m_polishmenu->addAction(m_polishFriendly);
    m_polishmenu->addAction(m_polishHumor);
    m_polishmenu->addAction(m_polishPassionate);
    m_polishmenu->installEventFilter(this);

    m_moreMenu = new DMenu(this);
    m_moreMenu->setMinimumWidth(92);
    m_moreMenu->installEventFilter(this);
    m_moreMenu->addAction(m_continueAction);
    m_moreMenu->addAction(m_expandAction);
    m_moreMenu->addAction(m_correctAction);
    m_moreMenu->addMenu(m_polishmenu);
    m_moreMenu->addSeparator();
    m_moreMenu->addAction(m_hiddenAction);

    QHBoxLayout *scribeWordsLayout = new QHBoxLayout;
    scribeWordsLayout->addWidget(m_lineSep1);
    scribeWordsLayout->addWidget(m_lineSep2);
    scribeWordsLayout->addWidget(m_lineSepSpace);
    scribeWordsLayout->addWidget(m_iconBtn);
    scribeWordsLayout->addWidget(m_searchBtn);
    scribeWordsLayout->addWidget(m_explainBtn);
    scribeWordsLayout->addWidget(m_summaryBtn);
    scribeWordsLayout->addWidget(m_translationBtn);
    scribeWordsLayout->addWidget(m_lineSep);
    scribeWordsLayout->addWidget(m_moreBtn);
    scribeWordsLayout->addWidget(m_closeBtn);
    scribeWordsLayout->addStretch();
    scribeWordsLayout->setSpacing(2);
    scribeWordsLayout->setAlignment(Qt::AlignCenter);
    scribeWordsLayout->setContentsMargins(6, 0, 6, 0);

    this->setLayout(scribeWordsLayout);
    setButtonHidden(true);
}

void WizardWrapper::initConnect()
{
    connect(m_iconBtn, &DIconButton::clicked, this, &WizardWrapper::onIconBtnClicked);
    connect(m_moreMenu, &QMenu::triggered, this, &WizardWrapper::onMoreMenuTriggered);
    connect(m_moreBtn, &WizardDPushButton::clicked, this, &WizardWrapper::showMenu);
    connect(m_searchBtn, &WizardDPushButton::clicked, this, &WizardWrapper::onButtonClicked);
    connect(m_explainBtn, &WizardDPushButton::clicked, this, &WizardWrapper::onButtonClicked);
    connect(m_summaryBtn, &WizardDPushButton::clicked, this, &WizardWrapper::onButtonClicked);
    connect(m_translationBtn, &WizardDPushButton::clicked, this, &WizardWrapper::onButtonClicked);
    //避免随航检测到mouseRelease事件后又弹出
    connect(m_closeBtn, &WizardDPushButton::clicked, this, [&] {
        QTimer::singleShot(1, this, &WizardWrapper::onCloseWidget);
    });

    connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &WizardWrapper::onUpdateSystemTheme);

}

void WizardWrapper::paintEvent(QPaintEvent *event)
{
    QStyleOption opt;
    opt.initFrom(this);
    QPainter painter(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);

    DPalette parentPb = DGuiApplicationHelper::instance()->applicationPalette();
    QColor backgroundColor = parentPb.color(DPalette::Normal, DPalette::NColorTypes);
    QRect rect = this->rect();

    painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing);
    painter.setBrush(backgroundColor);
    painter.setPen(Qt::NoPen);
    painter.drawRect(rect);
}

bool WizardWrapper::eventFilter(QObject *watched, QEvent *event)
{
    // 显示工具栏逻辑
    if (event->type() == QEvent::Enter) {
        m_mouseInside = true;
        if (watched == m_iconBtn && !m_isExtend) {
            QRect iconRect = this->geometry();
            QTimer::singleShot(500, this, [ = ]{
                if (!m_isExtend && iconRect.contains(QCursor::pos())) {
                    setButtonHidden(false);
                    adjustShowPos(m_screenRect, m_cursorPos);
                    move(m_cursorPos);
                    this->show();
                    this->adjustSize();
                }
            });
        }
    } else if (event->type() == QEvent::Leave && watched != m_iconBtn) {
        m_mouseInside = false;
    }

    // 拖动逻辑
    if (!ESystemContext::isTreeland() && m_isExtend
            && (watched == m_iconBtn || watched == m_searchBtn || watched == m_explainBtn
                || watched == m_summaryBtn || watched == m_translationBtn
                || watched == m_moreBtn || watched == m_closeBtn)) {
        if (event->type() == QEvent::Enter) {
            this->setCursor(Qt::CursorShape::ArrowCursor);
        } else if (event->type() == QEvent::Leave) {
            this->setCursor(Qt::CursorShape::OpenHandCursor);
        }
    }

    return DBlurEffectWidget::eventFilter(watched, event);
}

void WizardWrapper::mousePressEvent(QMouseEvent *event)
{
//    qDebug() << event;
    if (!ESystemContext::isTreeland() && m_isExtend) {
        if (event->button() == Qt::LeftButton) {
            this->setCursor(Qt::CursorShape::ClosedHandCursor);
            m_dragging = true;
            m_dragStartPos = event->globalPos() - frameGeometry().topLeft();
            return;
        }
    }

    DBlurEffectWidget::mousePressEvent(event);
}

void WizardWrapper::mouseMoveEvent(QMouseEvent *event)
{
//    qDebug() << event;
    if (!ESystemContext::isTreeland() && m_isExtend) {
        if (m_dragging) {
            this->setCursor(Qt::CursorShape::ClosedHandCursor);
            this->move(event->globalPos() - m_dragStartPos);
            return;
        }
    }

    DBlurEffectWidget::mouseMoveEvent(event);
}

void WizardWrapper::mouseReleaseEvent(QMouseEvent *event)
{
//    qDebug() << event;
    if (!ESystemContext::isTreeland() && m_isExtend) {
        if (event->button() == Qt::LeftButton) {
            m_dragging = false;
            this->setCursor(Qt::CursorShape::OpenHandCursor);
            return;
        }
    }

    DBlurEffectWidget::mouseReleaseEvent(event);
}

#ifdef COMPILE_ON_QT6
void WizardWrapper::enterEvent(QEnterEvent *event)
#else
void WizardWrapper::enterEvent(QEvent *event)
#endif
{
//    qDebug() << event;
    if (!ESystemContext::isTreeland() && m_isExtend) {
        this->setCursor(Qt::CursorShape::OpenHandCursor);
    }
    DBlurEffectWidget::enterEvent(event);
}

void WizardWrapper::leaveEvent(QEvent *event)
{
//    qDebug() << event;
    if (!ESystemContext::isTreeland() && m_isExtend) {
        this->setCursor(Qt::CursorShape::ArrowCursor);
    }
    DBlurEffectWidget::leaveEvent(event);
}

void WizardWrapper::onUpdateSystemTheme(const DGuiApplicationHelper::ColorType &themeType)
{
    if (themeType == DGuiApplicationHelper::LightType) {
        if(m_lineSep) {
            DPalette sepPalette = m_lineSep->palette();
            sepPalette.setColor(DPalette::Window, QColor(0, 0, 0, 25));
            m_lineSep->setPalette(sepPalette);
            m_lineSep1->setPalette(sepPalette);
            m_lineSep2->setPalette(sepPalette);
        }
    } else {
        if(m_lineSep) {
            DPalette sepPalette = m_lineSep->palette();
            sepPalette.setColor(DPalette::Window, QColor(255, 255, 255, 25));
            m_lineSep->setPalette(sepPalette);
            m_lineSep1->setPalette(sepPalette);
            m_lineSep2->setPalette(sepPalette);
        }
    }
    update();
}

void WizardWrapper::showScribeWordsAtCursorPosition(QRect screenRect, QPoint& point, bool isMouseRelease, bool isShortcut)
{
    m_screenRect = screenRect;
    m_cursorPos = point;
    if(isMouseRelease || isShortcut){
        if (isShortcut) {
            QList<QScreen *> screens = QGuiApplication::screens();
            for(QScreen *screen : screens) {
                if (screen->geometry().contains(m_cursorPos)) {
                    m_screenRect = screen->geometry();
                }
            }
            m_cursorPos = m_screenRect.center() - QPoint(this->rect().width() / 2, 0);
        }
        else {
            adjustShowPos(m_screenRect, m_cursorPos);
        }
        move(m_cursorPos);
        close();
        m_isVisible = false;
        showWizardWrapperWithAnimation();
    }
}

void WizardWrapper::initAnimation()
{
    m_animation = new QPropertyAnimation(this, "windowOpacity");
    m_animation->setDuration(300);
    m_animation->setStartValue(0.0);
    m_animation->setEndValue(1.0);
    m_animation->setEasingCurve(QEasingCurve::OutInQuad);
    return;
}

void WizardWrapper::showWizardWrapperWithAnimation()
{
    this->setWindowOpacity(0.0);
    this->show();
    m_isVisible = true;
    m_mouseInside = false;
#ifdef COMPILE_ON_V25
    if (ESystemContext::isTreeland()) {
        DDEShellWayland::get(windowHandle())->setAutoPlacement(1);
        DDEShellWayland::get(windowHandle())->setSkipDockPreview(true);
        DDEShellWayland::get(windowHandle())->setSkipMutiTaskView(true);
        DDEShellWayland::get(windowHandle())->setSkipSwitcher(true);
        DDEShellWayland::get(windowHandle())->setAcceptKeyboardFocus(false);
    }
#endif
    update();
    adjustSize();
    m_animation->start();
}

void WizardWrapper::onMoreMenuTriggered(const QAction *action)
{
    if (!WelcomeDialog::isAgreed()) {
        this->close();
        m_isVisible = false;
        WelcomeDialog::instance(false)->exec();
        return;
    }

    int wizardtype;
    if (action == m_hiddenAction)
        wizardtype = WordWizard::WIZARD_TYPE_HIDDEN;
    else if (action == m_continueAction)
        wizardtype = WordWizard::WIZARD_TYPE_RENEW;
    else if (action == m_expandAction)
        wizardtype = WordWizard::WIZARD_TYPE_EXTEND;
    else if (action == m_correctAction)
        wizardtype = WordWizard::WIZARD_TYPE_CORRECT;
    else if (action == m_polishFormal)
        wizardtype = WordWizard::WIZARD_TYPE_POLISH0;
    else if (action == m_polishFriendly)
        wizardtype = WordWizard::WIZARD_TYPE_POLISH1;
    else if (action == m_polishHumor)
        wizardtype = WordWizard::WIZARD_TYPE_POLISH2;
    else if (action == m_polishPassionate)
        wizardtype = WordWizard::WIZARD_TYPE_POLISH3;
    emit signalMoreMenuTriggered(wizardtype, m_cursorPos + QPoint(this->rect().width() / 2, 0));
}

void WizardWrapper::onButtonClicked()
{
    if (sender() != m_searchBtn && !WelcomeDialog::isAgreed()) {
        this->close();
        m_isVisible = false;
        WelcomeDialog::instance(false)->exec();
        return;
    }

    int wizardtype;
    if (sender() == m_searchBtn)
        wizardtype = WordWizard::WIZARD_TYPE_SEARCH;
    else if (sender() == m_explainBtn)
        wizardtype = WordWizard::WIZARD_TYPE_EXPLAIN;
    else if (sender() == m_summaryBtn)
        wizardtype = WordWizard::WIZARD_TYPE_SUMMARIZE;
    else if (sender() == m_translationBtn)
        wizardtype = WordWizard::WIZARD_TYPE_TRANSLATE;

    emit signalRequestServer();
    emit signalWizardBtnClicked(wizardtype, m_cursorPos + QPoint(this->rect().width() / 2, 0));
}

void WizardWrapper::showMenu()
{
    emit signalRequestServer();
    adjustSize();
    m_moreMenu->exec(m_moreBtn->mapToGlobal(m_moreBtn->rect().bottomLeft() + QPoint(0, 5)));
    m_moreBtn->update();
}

void WizardWrapper::onCloseWidget()
{
    this->close();
    m_isVisible = false;
    if (isFirstClose()) {
        DDialog dialog("",tr("After selecting the text, press the Super+Space bar can also wake up the UOS AI FollowAlong."));
        dialog.setFixedWidth(380);
        dialog.setIcon(QIcon(":assets/images/tips.svg"));
        dialog.addButton(tr("Ok", "button"), true, DDialog::ButtonNormal);
        dialog.exec();
        DConfigManager::instance()->setValue(WORDWIZARD_GROUP, WORDWIZARD_ISFIRSTCLOSE, false);
    }
    emit signalCloseBtnClicked();
}

void WizardWrapper::onIconBtnClicked()
{
    this->close();
    m_isVisible = false;
    emit signalIconBtnClicked();
}

void WizardWrapper::adjustShowPos(const QRect &screenRect, QPoint &pos)
{
    adjustSize();
    pos = pos - QPoint(this->rect().width() / 2, 0);

    QRect widgetRect(pos.x(), pos.y(), this->rect().width(), this->rect().height());
    if (screenRect.contains(widgetRect))
        return;
    if (screenRect.left() > widgetRect.left())
        pos.setX(screenRect.left());
    if (screenRect.top() > widgetRect.top())
        pos.setY(screenRect.top());
    if (screenRect.right() < widgetRect.right())
        pos.setX(screenRect.right() - widgetRect.width());
    if (screenRect.bottom() < widgetRect.bottom())
        pos.setY(widgetRect.top() - 2 * widgetRect.height());
}

void WizardWrapper::isShowHiddenAction(bool isShow)
{
    m_hiddenAction->setVisible(isShow);
}

bool WizardWrapper::isFirstClose()
{
    return DConfigManager::instance()->value(WORDWIZARD_GROUP, WORDWIZARD_ISFIRSTCLOSE).toBool();
}

void WizardWrapper::setButtonHidden(bool isHidden)
{
    QList<WizardDPushButton *> buttons = this->findChildren<WizardDPushButton *>();
    auto hLayout = this->findChild<QHBoxLayout *>();
    if (isHidden) {
        this->setFixedSize(32, 32);
        for (WizardDPushButton *button : buttons)
            button->hide();
        m_iconBtn->setFixedSize(QSize(20, 20));
        m_iconBtn->setIconSize(QSize(20, 20));
        m_lineSep->hide();
        m_lineSep1->hide();
        m_lineSep2->hide();
        m_lineSepSpace->hide();
        if (hLayout)
            hLayout->setContentsMargins(6, 0, 6, 0);
    } else {
        this->setMaximumWidth(QWIDGETSIZE_MAX);
        for (WizardDPushButton *button : buttons) {
            button->show();
            button->setHoverStatus(false);
        }
        this->setFixedHeight(m_searchBtn->height() + 6);
        m_iconBtn->setFixedSize(QSize(16, 16));
        m_iconBtn->setIconSize(QSize(16, 16));
        m_lineSep->show();
        m_lineSep1->show();
        m_lineSep2->show();
        m_lineSepSpace->show();
        if (hLayout)
            hLayout->setContentsMargins(9, 0, 6, 0);

        // tid:1001600001 event:followalong
        ReportIns()->writeEvent(report::FollowalongPoint().assemblingData());
    }
    m_isExtend = !isHidden;
    adjustSize();
}

