/*
 * Copyright (C) 2017 ~ 2018 Deepin Technology Co., Ltd.
 *
 * Author:     kirigaya <kirigaya@mkacg.com>
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mainwindow.h"
#include "ddlog.h"

#include <unistd.h>
#include <DSysInfo>
#include <QDesktopServices>

static const int kWindowWidth = 1000;
static const int kWindowHeight = 700;

MainWindow::MainWindow(DWidget *parent)
    : DMainWindow(parent)
    , m_index(0)
    , m_current(nullptr)
    , m_last(nullptr)
    , m_currentAni(new QPropertyAnimation(this))
    , m_lastAni(new QPropertyAnimation(this))
    , m_currentOpacityAni(new QPropertyAnimation(this))
    , m_lastOpacityAni(new QPropertyAnimation(this))
    , m_settings(new QSettings("deepin", "dde-introduction"))
    , m_title(new DLabel(this))
{
    qCInfo(app) << "Current CPU architecture:" << QSysInfo::currentCpuArchitecture();
    setWindowFlags(Qt::CustomizeWindowHint);

    titlebar()->setMenuVisible(false);
    titlebar()->setFixedHeight(50);
    titlebar()->setIcon(QIcon::fromTheme("dde-introduction"));
    QPalette pa;
    pa.setColor(QPalette::Base, Qt::white);
    titlebar()->setPalette(pa);
    //适配1050Dtk不再聚焦TitleBar，现在也无需自绘了
    QWidget *EmptyWidget = new QWidget(this);
    EmptyWidget->setFocusPolicy(Qt::TabFocus);
    EmptyWidget->setGeometry(0, 0, 0, 0);
    setTabOrder(m_pCloseBtn, EmptyWidget);
    setTitlebarShadowEnabled(false);

    m_isFirst = m_settings->value("IsFirst", true).toBool();
    m_settings->setValue("IsFirst", false);

    qCDebug(app) << "Initializing MainWindow components";
    initUI();
    initConnect();
    qCDebug(app) << "MainWindow initialization completed";

    //设置首次启动的tab顺序
    setTabOrder(m_previousBtn, m_nextBtn);
    //适配1050Dtk不再聚焦TitleBar
    setTabOrder(m_pCloseBtn, EmptyWidget);
}

MainWindow::~MainWindow()
{
    qCInfo(app) << "MainWindow destructor called";

    QFile file(DDE_STARTGUIDE_PATH);
    if (file.exists()) {
        QProcess *pStartAppProcess = new QProcess(this);
        pStartAppProcess->startDetached(DDE_STARTGUIDE_PATH);
    }

    // Use _exit() to terminate immediately without triggering C++ destructor chain.
    // exit() would cause Qt's widget tree destruction which races with mpv's internal
    // X11/rendering threads still running in libmpv.so -> BadDrawable -> SIGSEGV.
    // _exit() lets the OS reclaim all resources (memory, X11 connections, mpv threads).
    _exit(0);
}

void MainWindow::delayInitVideo()
{
    qCDebug(app) << "Delaying video initialization";
    m_delayInit = true;
    QTimer::singleShot(1500, this, [ this ]() {
        WidgetManager::Instance()->delayInit();
        m_loadVideoLoop.quit();
        m_delayInit = false;
    });
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if (WidgetManager::Instance()->getCurrentWidget().type == PageType::StyleType) {
        static_cast<DesktopModeModule *>(
            static_cast<BaseModuleWidget *>(m_current)->getModel())
        ->keyPressEvent(event);
    }

    QMainWindow::keyPressEvent(event);
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    // In a scale factor of 1.75, the height will be rounded to 699,
    // less than minimum height, adjust it.
    int adjustOffset = ceil(devicePixelRatioF());
    if (adjustOffset > 0) {
        auto size = event->size();
        bool widthError = size.width() < kWindowWidth;
        bool heightError = size.height() < kWindowHeight;

        if (widthError || heightError) {
            setFixedSize(kWindowWidth + (widthError ? adjustOffset : 0),
                         kWindowHeight + (heightError ? adjustOffset : 0));
            return;
        }
    }

    DMainWindow::resizeEvent(event);
}

/*******************************************************************************
 1. @函数:    previous
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    上一步按钮响应函数
*******************************************************************************/
void MainWindow::previous()
{
    qCDebug(app) << "Previous button clicked, current index:" << m_index;

    if (m_currentAni->state() == QPropertyAnimation::Running) {
        qCDebug(app) << "Animation is running, skip previous operation";
        return;
    }

    WidgetManager::Instance()->handoffPrevWidget();
    //创建上一步按钮选择的界面
    updateModule(--m_index);

    m_currentAni->setDuration(500);
    m_currentAni->setEasingCurve(QEasingCurve::InOutCubic);
    m_currentAni->setStartValue(QPoint(m_last->x() - m_last->width(), 0));
    m_currentAni->setEndValue(QPoint(0, 0));

    m_currentOpacityAni->setDuration(800);
    m_currentOpacityAni->setStartValue(0.5);
    m_currentOpacityAni->setEndValue(1);

    m_lastAni->setDuration(500);
    m_lastAni->setEasingCurve(QEasingCurve::InOutCubic);
    m_lastAni->setStartValue(m_last->rect().topLeft());
    m_lastAni->setEndValue(m_last->rect().topRight());

    m_lastOpacityAni->setDuration(500);
    m_lastOpacityAni->setStartValue(1);
    m_lastOpacityAni->setEndValue(0);

    qCDebug(app) << "Starting previous page animation";
    m_currentAni->start();
//    m_currentOpacityAni->start();
    m_lastAni->start();
    m_lastOpacityAni->start();
}

/*******************************************************************************
 1. @函数:    next
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    下一步按钮响应函数
*******************************************************************************/
void MainWindow::next()
{
    qCDebug(app) << "Next button clicked, current index:" << m_index;

    if (m_currentAni->state() == QPropertyAnimation::Running || m_loadVideoLoop.isRunning()) {
        qCDebug(app) << "Animation or video loading is running, skip next operation";
        return;
    }

    if (!WidgetManager::Instance()->canHandoff() && m_delayInit)
        m_loadVideoLoop.exec();

    WidgetManager::Instance()->handoffNextWidget();
    //previous函数中添加的窗口特效是否支持判断，因为updateModule函数中第三步判断有问题，只有++
    // create new QWidget, change pointer
    //创建下一步按钮选择的界面
    updateModule(++m_index);

    m_lastAni->setDuration(500);
    m_lastAni->setEasingCurve(QEasingCurve::InOutCubic);
    m_lastAni->setStartValue(m_last->rect().topLeft());
    m_lastAni->setEndValue(QPoint(m_last->x() - m_last->width(), 0));

    m_lastOpacityAni->setDuration(500);
    m_lastOpacityAni->setStartValue(1);
    m_lastOpacityAni->setEndValue(0);

    m_currentAni->setDuration(500);
    m_currentAni->setEasingCurve(QEasingCurve::InOutCubic);
    m_currentAni->setStartValue(QPoint(m_last->rect().topRight()));
    m_currentAni->setEndValue(QPoint(0, 0));

    m_currentOpacityAni->setDuration(800);
    m_currentOpacityAni->setStartValue(0.5);
    m_currentOpacityAni->setEndValue(1);

    qCDebug(app) << "Starting next page animation";
    m_currentAni->start();
//    m_currentOpacityAni->start();
    m_lastAni->start();
    m_lastOpacityAni->start();
    qCDebug(app) << "Exit next(), switched to index:" << m_index;
}

void MainWindow::finishedAndClose()
{
    qCDebug(app) << "Finished and closing window";
    if (m_isFirst) {
        QDBusInterface networkInterface("org.freedesktop.NetworkManager",
                                 "/org/freedesktop/NetworkManager",
                                 "org.freedesktop.NetworkManager",
                                 QDBusConnection::systemBus());
        int state = networkInterface.property("State").toInt();
        if (state >= 70) {
            QDBusInterface Interface("com.home.appstore.client",
                                     "/com/home/appstore/client",
                                     "com.home.appstore.client",
                                     QDBusConnection::sessionBus());
            Interface.call("openInstalledNecessaryPage");
        }

    }
    this->close();
}

/*******************************************************************************
 1. @函数:    slotTheme
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    主题变化响应函数
*******************************************************************************/
void MainWindow::slotTheme()
{
    if (m_nextBtn == nullptr) return;
    DPalette nextPa = m_nextBtn->palette();
    nextPa.setColor(DPalette::ButtonText, QColor(65, 77, 104, 255));
    m_nextBtn->setPalette(nextPa);
    DPalette pl = this->palette();
    pl.setColor(DPalette::Window, Qt::white);
    this->setPalette(pl);
    m_pCloseBtn->setIcon(QIcon(":/resources/close_normal_light.svg"));
    this->setForegroundRole(DPalette::Window);
    this->setBackgroundRole(DPalette::Window);
}

void MainWindow::initUI()
{
    qCDebug(app) << "Initializing MainWindow UI";
    //设置圆角
//    DPlatformWindowHandle handle(this);
    m_fakerWidget = new DWidget(this);
    QPalette pal(m_fakerWidget->palette());
    pal.setColor(QPalette::Window, Qt::white);
    m_fakerWidget->setAutoFillBackground(true);
    m_fakerWidget->setPalette(pal);

    setFixedSize(kWindowWidth, kWindowHeight);
    
    m_fakerWidget->setFixedSize(QSize(width(), height() - titlebar()->height() - 80));
    m_fakerWidget->move(0, titlebar()->height());
    WidgetManager::Instance()->setParents(m_fakerWidget);
    // set first video mute off
    auto introWidget = WidgetManager::Instance()->getCurrentWidget();
    WidgetManager::Instance()->setVideoMute(introWidget, false);
    m_current = introWidget.w;

    m_pCloseBtn = new DIconButton(this);
    m_pCloseBtn->setFlat(true);
    m_pCloseBtn->setFixedSize(51, 51);
    m_pCloseBtn->setIconSize(QSize(51, 51));
    m_pCloseBtn->move(rect().topRight() - QPoint(m_pCloseBtn->width(), -1));
#ifdef DTKWIDGET_CLASS_DSizeMode
    if (DGuiApplicationHelper::instance()->sizeMode() == DGuiApplicationHelper::CompactMode) {
        m_pCloseBtn->setFixedSize(33, 33);
        m_pCloseBtn->setIconSize(QSize(33, 33));
        m_pCloseBtn->move(rect().topRight() - QPoint(m_pCloseBtn->width(), -9));
    }
    connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::sizeModeChanged, this, [ = ](DGuiApplicationHelper::SizeMode sizeMode) {
        if (sizeMode == DGuiApplicationHelper::NormalMode) {
            m_pCloseBtn->setFixedSize(51, 51);
            m_pCloseBtn->setIconSize(QSize(51, 51));
            m_pCloseBtn->move(rect().topRight() - QPoint(m_pCloseBtn->width(), -1));
        } else {
            m_pCloseBtn->setFixedSize(33, 33);
            m_pCloseBtn->setIconSize(QSize(33, 33));
            m_pCloseBtn->move(rect().topRight() - QPoint(m_pCloseBtn->width(), -4));
        }
    });
#endif
    connect(m_pCloseBtn, &DIconButton::clicked, this, &MainWindow::close);

    m_nextBtn = new DSuggestButton(tr("Next Page"), this);
    m_nextBtn->setFixedSize(88, 36);
    QGraphicsDropShadowEffect *nextBtnShadow = new QGraphicsDropShadowEffect(this);
    nextBtnShadow->setOffset(0, 2);
    nextBtnShadow->setColor(QColor(0, 0, 0, int(0.05 * 255)));
    nextBtnShadow->setBlurRadius(6);
    m_nextBtn->setGraphicsEffect(nextBtnShadow);
    m_nextBtn->move(892, 642);

    m_previousBtn = new DPushButton(tr("Previous Page"), this);
    m_previousBtn->setFixedSize(88, 36);
    QGraphicsDropShadowEffect *previousBtnShadow = new QGraphicsDropShadowEffect(this);
    previousBtnShadow->setOffset(0, 2);
    previousBtnShadow->setColor(QColor(0, 0, 0));
    previousBtnShadow->setBlurRadius(6);
    m_previousBtn->setGraphicsEffect(nextBtnShadow);
    m_previousBtnPoint.setX(794);
    m_previousBtnPoint.setY(642);
    m_previousBtn->move(m_previousBtnPoint);
    QFontMetrics fm(m_previousBtn->font());
    int textWidth = fm.horizontalAdvance(m_previousBtn->text()) + 20;

    m_previousBtn->hide();

    m_doneBtn = new DSuggestButton(tr("Getting Started"), this);
    m_doneBtn->setFixedSize(88, 36);
    m_doneBtn->setGraphicsEffect(nextBtnShadow);
    m_doneBtn->move(892, 642);
    int doneBtnWidth = fm.horizontalAdvance(m_doneBtn->text()) + 20;

    if (textWidth < doneBtnWidth) {
        textWidth = doneBtnWidth;
    }

    bool vFlag = false;
    if (textWidth > m_previousBtn->width()) {
        m_previousBtnPoint.setX(m_previousBtnPoint.x() - 2 * (textWidth - m_previousBtn->width()));
        m_previousBtn->setFixedWidth(textWidth);
        m_nextBtn->setFixedWidth(textWidth);
        m_previousBtn->move(m_previousBtnPoint);
        m_nextBtn->move(m_previousBtnPoint.x() + textWidth + 10, 642);
        vFlag = true;
    }

    if (vFlag) {
        //int offect = doneBtnWidth - m_doneBtn->width();
        m_doneBtn->move(m_previousBtnPoint.x() + textWidth + 10, 642);;
        m_doneBtn->setFixedWidth(textWidth);
    }
    m_doneBtn->hide();

    m_indexDots = new IndexDotsWidget(WidgetManager::Instance()->getWidgetSize(), this);
    m_indexDots->move(width() / 2 - m_indexDots->width() / 2, 656);
    m_indexDots->show();

    DFontSizeManager::instance()->bind(m_title, DFontSizeManager::T5, QFont::DemiBold);
    m_title->setFixedSize(width(), 48);
    m_title->setForegroundRole(DPalette::TextTitle);
    m_title->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
    m_title->move(0, 0);

    //首次启动欢迎时关闭键可以使用Tab键聚焦
    m_pCloseBtn->setFocusPolicy(Qt::TabFocus);
    m_pCloseBtn->show();

    //上一步和下一步选择的界面的动画
    m_currentAni->setPropertyName("pos");
    m_currentOpacityAni->setPropertyName("opacity");
    //当前还没变化的界面的动画
    m_lastAni->setPropertyName("pos");
    m_lastOpacityAni->setPropertyName("opacity");
    m_current->resize(width() + 2, height() - titlebar()->height() - 80 + 2);
    m_current->move(-1, -1);//因为有白边框的问题
    m_current->show();
    slotTheme();
}

void MainWindow::initConnect()
{
    qCDebug(app) << "Initializing MainWindow signal connections";
    //主题变化响应
    connect(m_nextBtn, &DSuggestButton::clicked, this, &MainWindow::next);
    connect(m_nextBtn, &DSuggestButton::clicked, WidgetManager::Instance(), &WidgetManager::delayInit);
    connect(m_previousBtn, &DPushButton::clicked, this, &MainWindow::previous);
    connect(m_currentAni, &QPropertyAnimation::finished, this, &MainWindow::animationHandle);
    connect(m_doneBtn, &DSuggestButton::clicked, this, &MainWindow::finishedAndClose);
}

/*******************************************************************************
 1. @函数:    bindAnimation
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    绑定需要动画的界面
*******************************************************************************/
void MainWindow::bindAnimation()
{
    QGraphicsOpacityEffect *Opacity1 = new QGraphicsOpacityEffect(m_current);
    m_current->setGraphicsEffect(Opacity1);
    Opacity1->setOpacity(1);

    QGraphicsOpacityEffect *Opacity2 = new QGraphicsOpacityEffect(m_last);
    m_last->setGraphicsEffect(Opacity2);
    Opacity2->setOpacity(1);

    m_currentAni->setTargetObject(m_current);
    m_currentOpacityAni->setTargetObject(Opacity1);
    m_lastAni->setTargetObject(m_last);
    m_lastOpacityAni->setTargetObject(Opacity2);
}

/*******************************************************************************
 1. @函数:    updateModule
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    根据index值进行欢迎四个界面的创建,并进行动画绑定
*******************************************************************************/
void MainWindow::updateModule(const int index)
{
    qCDebug(app) << "Updating module to index:" << index;
//    if (m_videoWidgetList.size() <= index)
//        m_loadVideoLoop.exec();
    m_doneBtn->hide();
    m_nextBtn->show();
    m_previousBtn->move(m_previousBtnPoint);
    m_previousBtn->show();

    m_last = m_current;
    m_current = WidgetManager::Instance()->getCurrentWidget().w;
    switch (WidgetManager::Instance()->getCurrentWidget().type) {
    case PageType::videoType:
#ifndef DISABLE_VIDEO
        static_cast<VideoWidget *>(static_cast<BaseModuleWidget *>(m_current)->getModel())->startPlay();
#endif
        m_title->setText("");
        break;
    case PageType::StyleType:
        m_fakerWidget->setFocus();
        m_title->setText(tr("Choose a desktop mode"));
        break;
    case PageType::FinishType:
        m_fakerWidget->setFocus();
        m_title->setText(tr("Getting Ready"));
        m_nextBtn->hide();
        m_doneBtn->show();
        break;
    default:
        break;
    }

    m_indexDots->setCurrentIndex(index);
    m_current->show();
    if (index == 0)
        m_previousBtn->hide();

    bindAnimation();
    qCDebug(app) << "Animation bound for current and last widgets";
}

/*******************************************************************************
 1. @函数:    animationHandle
 2. @作者:
 3. @日期:    2020-12-08
 4. @说明:    m_currentAni动画结束后删除m_last保存的界面
*******************************************************************************/
void MainWindow::animationHandle()
{
    qCDebug(app) << "Animation completed for index:" << m_index;
    if (m_last) {
        auto *baseModule = dynamic_cast<BaseModuleWidget *>(m_last);
        if (baseModule) {
#ifndef DISABLE_VIDEO
            auto *video = dynamic_cast<VideoWidget *>(baseModule->getModel());
            if (video) {
                video->pause();
            }
#endif
        }
    }
}

void MainWindow::stopVideoIfNeeded(DWidget *widget)
{
    auto *baseModule = dynamic_cast<BaseModuleWidget *>(widget);
    if (!baseModule) {
        return;
    }

#ifndef DISABLE_VIDEO
    auto *video = dynamic_cast<VideoWidget *>(baseModule->getModel());
    if (!video) {
        return;
    }

    video->stopBeforeDestroy();
#endif
}

/*******************************************************************************
 1. @函数:    mousePressEvent
 2. @作者:
 3. @日期:    2025-01-14
 4. @说明:    处理鼠标按下事件，实现窗口拖拽功能
*******************************************************************************/
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        qCDebug(app) << "MainWindow::mousePressEvent - Starting drag at position:" << event->pos();
        m_isDragging = true;
        m_dragStartPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
        return;
    }
    
    DMainWindow::mousePressEvent(event);
}

/*******************************************************************************
 1. @函数:    mouseReleaseEvent
 2. @作者:
 3. @日期:    2025-01-14
 4. @说明:    处理鼠标释放事件，结束窗口拖拽
*******************************************************************************/
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && m_isDragging) {
        qCDebug(app) << "MainWindow::mouseReleaseEvent - Ending drag";
        m_isDragging = false;
        return;
    }
    
    DMainWindow::mouseReleaseEvent(event);
}

/*******************************************************************************
 1. @函数:    mouseMoveEvent
 2. @作者:
 3. @日期:    2025-01-14
 4. @说明:    处理鼠标移动事件，实现窗口拖拽移动
*******************************************************************************/
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (m_isDragging && (event->buttons() & Qt::LeftButton)) {
        QPoint newPos = event->globalPosition().toPoint() - m_dragStartPosition;
        if (newPos.y() < 0) {
            newPos.setY(0);
        }
        move(newPos);
        qCDebug(app) << "MainWindow::mouseMoveEvent - Dragging to position:" << newPos;
        return;
    }
    
    DMainWindow::mouseMoveEvent(event);
}
