/*
 * Kylin-video
 *
 * Copyright (C) 2021, Tianjin KYLIN Information Technology Co., Ltd.
 *
 * 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
 * (at your option) 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 <https://www.gnu.org/licenses/>.
 *
 * Authors: Liu Cong <liucong1@kylinos.cn>
 *
 */

#include "topwindow.h"

#include <QDebug>
#include <QTimer>
#include <QMimeData>
#include <QMouseEvent>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QStackedWidget>
#include <QDragEnterEvent>
#include <QGuiApplication>
#include <QFileSystemWatcher>
#include <KF5/KWindowSystem/kwindowsystem.h>
#include <ukui-log4qt.h>

#include "global/xatom-helper.h"

#include "homepage.h"
#include "titlewidget.h"
#include "contralbar.h"
#include "kmenu.h"
#include "minimodeshade.h"
#include "playlistwidget.h"
#include "eventpasswidget.h"

#include "global/extensions.h"
#include "global/global.h"

using namespace Global;

TopWindow::TopWindow(QWidget *parent) :
    QDialog(parent),
    m_isMove(false),
    m_isMaxWindow(false),
    m_isFullScreen(false),
    m_canHideAll(true),
    m_isMiniMode(false),
    m_parentWidget(parent),
    m_pressPos(QPoint(0, 0))
{
    setProperty("useStyleWindowManager", false);
    setAttribute(Qt::WA_TranslucentBackground);
    setObjectName("topWindow");
    setMinimumSize(NormalModeSize);

    MotifWmHints hints1;
    hints1.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
    hints1.functions = MWM_FUNC_ALL;
    hints1.decorations = MWM_DECOR_BORDER;
    XAtomHelper::getInstance()->setWindowMotifHint(winId(), hints1);

    initStackedWidget();
    initTitleWidget();
    initContralBar();
    initPlayListWidget();
    initMiniModeShade();
    initGlobalSig();

    setAcceptDrops(true);
}

void TopWindow::showMax()
{
    if (isFullScreen()) {
        return;
    }

    if (m_isMaxWindow) {
        KWindowSystem::clearState(winId(), NET::Max);
        KWindowSystem::clearState(m_parentWidget->winId(), NET::Max);
        m_isMaxWindow = false;
        m_titleWidget->updateMaxButtonStatus(false);
    }
    else {
        KWindowSystem::setState(winId(), NET::Max);
        KWindowSystem::setState(m_parentWidget->winId(), NET::Max);
        m_isMaxWindow = true;
        m_titleWidget->updateMaxButtonStatus(true);
    }
}

void TopWindow::showMin()
{
    m_playListWidget->slotHide();
    emit sigMinSize();
}

void TopWindow::showTitleMenu()
{
    m_titleMenu->exec(QPoint(m_titleWidget->getMenuBtnX()+mapToGlobal(QPoint(0,0)).x(),
                             mapToGlobal(QPoint(0,0)).y()+m_titleWidget->height()-5));
}

void TopWindow::showNormalMode()
{
    if (!m_isMiniMode)
        return;
    m_contralBar->setMiniMode(false);
    m_titleWidget->setMiniMode(false);
    m_playListWidget->show();
    setMinimumSize(NormalModeSize);
    setMaximumSize(99999, 99999);
//    setGeometry(m_normalRect);
    resize(NormalModeSize);
    m_eventPassWidget->setMouseUsed(true);
    m_miniModeShade->hide();
    m_isMiniMode = false;
}

void TopWindow::showMiniMode()
{
    if (m_isMiniMode || isFullScreen())
        return;

    int delay = 0;
    if (m_isMaxWindow) {
        delay = 200;
        KWindowSystem::clearState(winId(), NET::Max);
        KWindowSystem::clearState(m_parentWidget->winId(), NET::Max);
        m_isMaxWindow = false;
        m_titleWidget->updateMaxButtonStatus(false);
    }

    m_isMiniMode = true;
    m_contralBar->setMiniMode(true);
    m_titleWidget->setMiniMode(true);
    m_titleWidget->hide();
    m_contralBar->hide();
    m_playListWidget->hide();

    QTimer::singleShot(delay, [this](){
        setMinimumSize(MiniModeSize);
        resize(MiniModeSize);
        m_eventPassWidget->setMouseUsed(false);
        m_miniModeShade->show();
        m_miniModeShade->raise();
    });
}

void TopWindow::slotShowFullScreen(bool full)
{
    if (m_isFullScreen == full)
        return;
    if (m_isMiniMode)
        return;
    if (full)
    {
        m_isFullScreen = true;
        KWindowSystem::setState(m_parentWidget->winId(), NET::FullScreen);
        KWindowSystem::setState(winId(), NET::FullScreen);
        m_titleWidget->setButtonState(false);
    }
    else
    {
        KWindowSystem::clearState(m_parentWidget->winId(), NET::FullScreen);
        KWindowSystem::clearState(winId(), NET::FullScreen);
        m_titleWidget->setButtonState(true);
        m_isFullScreen = false;
    }
    m_canHideAll = true;
    hideAll(true);
}

void TopWindow::slotPlayStateChange(Mpv::PlayState state)
{
    if (state > 0) {
        m_stackedWidget->setCurrentIndex(1);
        m_titleWidget->setHomePage(false);
        if (isFullScreen()) {
            m_titleWidget->setButtonState(false);
        }
        m_eventPassWidget->setMouseUsed(true);
    }
    else {
        m_titleWidget->setTitle(tr("Video Player"), false);
        m_eventPassWidget->setMouseUsed(false);
    }
}

void TopWindow::slotPlayWidgetClicked()
{
    if(m_playListWidget->isShow())
        m_playListWidget->slotHide();
    else
        g_user_signal->playWidgetClick();
}

void TopWindow::hideAll(bool hide)
{
    if (m_stackedWidget->currentIndex() == 0)
        return;
    if (hide)
    {
        if(m_canHideAll)
        {
            m_contralBar->setHide();
            m_titleWidget->setHide();
            if (!m_playListWidget->isShow())
                m_playListWidget->setShowButton(false);
            // 播放列表是否需要隐藏 ?
        }
        else
        {
            // 鼠标要显示出来
            setCursor(Qt::ArrowCursor);
            m_eventPassWidget->setCursor(Qt::ArrowCursor);
            m_titleWidget->setCursor(Qt::ArrowCursor);
        }
    }
    else
    {
        if (!m_playListWidget->isShow()) {
            if (m_stackedWidget->currentIndex() == 1)
                m_contralBar->setShow();
            m_titleWidget->setShow();
            m_playListWidget->setShowButton(true);
        }
    }
}

void TopWindow::setHide()
{
    m_titleWidget->updateMaxButtonStatus(false);
    m_titleWidget->setButtonState(true);
    hide();
}

void TopWindow::openHelpDoc()
{
    // 帮助手册 先就分开写吧，快捷键不生效不知道为啥
    QDBusMessage m = QDBusMessage::createMethodCall("com.kylinUserGuide.hotel_1000",
                                                    "/",
                                                    "com.guide.hotel",
                                                    "showGuide");
    m << "kylin-video";
    if(QDBusConnection::sessionBus().isConnected())
        QDBusConnection::sessionBus().call(m);
}

void TopWindow::resetLayout()
{
    if (!m_isMiniMode && !m_isMaxWindow && !m_isFullScreen)
        m_normalRect = QRect(mapToGlobal(QPoint(0,0)), QSize(width(), height()));

    if (!m_isMaxWindow && !m_isFullScreen) {
        if (m_parentWidget) {
            m_parentWidget->resize(size());
        }
    }

    m_titleWidget->setGeometry(0, 0, width(), m_titleWidget->height());
    m_contralBar->setGeometry(120, height()-72, width()-240, 48);
    m_contralBar->setPreviewSize(size());
    m_stackedWidget->resize(size());

    m_homePage->resize(size());
    m_eventPassWidget->resize(size());

    // 只要大小改变，播放列表都要隐藏起来
    m_playListWidget->move(width() - 16, 0);
    m_playListWidget->resize(m_playListWidget->width(), height());
    m_playListWidget->updateHideIcon();

    if (m_miniModeShade)
        m_miniModeShade->resize(size());
}

void TopWindow::initGlobalSig()
{
    connect(g_user_signal, &GlobalUserSignal::sigOpenHelpDoc,   this, &TopWindow::openHelpDoc);
    connect(g_user_signal, &GlobalUserSignal::sigHideBar,       this, &TopWindow::hideAll);
    connect(g_core_signal, &GlobalCoreSignal::sigStateChange,   this, &TopWindow::slotPlayStateChange);
    connect(g_core_signal, &GlobalCoreSignal::sigFileInfoChange, [&](Mpv::FileInfo fi){
        m_titleWidget->setTitle(fi.file_path.split("/").back());
    });

    connect(g_user_signal, &GlobalUserSignal::sigChangeShowMode, [this](){
        if (m_stackedWidget->currentIndex() == 0)
            return;
        if (m_isMiniMode)
            showNormalMode();
        else
            showMiniMode();
    });
}

void TopWindow::initTitleWidget()
{
    m_titleMenu = new TitleMenu;
    connect(m_titleMenu, &TitleMenu::sigQuit, this, [this](){emit sigQuit();});

    m_titleWidget = new TitleWidget(this);
    m_titleWidget->raise();
    m_titleWidget->move(0, 0);
    m_titleWidget->setTitle(tr("Video Player"), false);

    connect(m_titleWidget, &TitleWidget::sigClose, this, [this](){
        resetLayout();
        emit sigClose();
    });
    connect(m_titleWidget, &TitleWidget::sigMaxSize, this, &TopWindow::showMax);
    connect(m_titleWidget, &TitleWidget::sigMiniSize, this, &TopWindow::showMin);
    connect(m_titleWidget, &TitleWidget::sigShowMenu, this, &TopWindow::showTitleMenu);
    connect(m_titleWidget, &TitleWidget::sigCanHide, [this](bool canHide){m_canHideAll = canHide;});
    connect(m_titleWidget, &TitleWidget::sigMiniMode, this, &TopWindow::showMiniMode);
}

void TopWindow::initContralBar()
{
    m_contralBar = new ContralBar(this);
    m_contralBar->hide();

    connect(m_contralBar, &ContralBar::sigFullScreen, this, &TopWindow::slotShowFullScreen);
    connect(m_contralBar, &ContralBar::sigCanHide, [this](bool canHide){m_canHideAll = canHide;});
}

void TopWindow::initStackedWidget()
{
    m_stackedWidget = new QStackedWidget(this);

    m_homePage = new HomePage;
    QHBoxLayout *lay_logo = new QHBoxLayout;
    lay_logo->setContentsMargins(0, 0, 0, 0);

    m_eventPassWidget = new EventPassWidget;
    connect(m_eventPassWidget, &EventPassWidget::mousePressed, this, &TopWindow::slotPlayWidgetClicked);

    m_stackedWidget->addWidget(m_homePage);
    m_stackedWidget->addWidget(m_eventPassWidget);
    m_stackedWidget->setCurrentIndex(0);
}

void TopWindow::initMiniModeShade()
{
    m_miniModeShade = new MiniModeShade(this);
    m_miniModeShade->hide();

    connect(m_miniModeShade, &MiniModeShade::sigClose, this, [this](){emit sigClose();});
    connect(m_miniModeShade, &MiniModeShade::sigShowNormal, this, &TopWindow::showNormalMode);
    connect(m_miniModeShade, &MiniModeShade::sigPlayPause, [&](){
        g_user_signal->sigPlayPause();
    });
}

void TopWindow::initPlayListWidget()
{
    m_playListWidget = new PlayListWidget(this);
    // 列表显示的时候隐藏标题栏和控制栏
    connect(g_user_signal, &GlobalUserSignal::sigShowPlayList, [&](){
        if(m_stackedWidget->currentIndex() == 1) {
            // 防止列表弹出的时候鼠标在播放界面上移动导致标题栏和控制栏弹出
            m_eventPassWidget->setMouseTracking(false);
            QTimer::singleShot(400, [this](){m_eventPassWidget->setMouseTracking(true);});

            m_canHideAll = true;
            hideAll(true);
        }
    });

    connect(m_playListWidget, &PlayListWidget::sigMove, [this](int distance){
        m_titleWidget->setGeometry(0, 0, width() - distance, m_titleWidget->height());
    });

    // 正在播放的文件改变，书签需要刷新
    connect(m_playListWidget->getPlayList(), &PlayList::sigPlayingFileMarkUpdate, [this](QVector<MarkItem> marks){
        m_contralBar->clearMark();
        foreach (MarkItem item, marks) {
            m_contralBar->addMark(item.m_markPos, item.m_describe);
        }
    });

    connect(m_playListWidget->getPlayList(), &PlayList::sigDeleteMark, [this](int mark_pos){
        m_contralBar->deleteMark(mark_pos);
    });

    // 正在播放时插入书签，需要刷新进度条书签
    connect(m_playListWidget->getPlayList(), &PlayList::sigInsertMark, [this](MarkItem mark){
        m_contralBar->insertMark(mark.m_markPos, mark.m_describe);
    });
}

void TopWindow::moveEvent(QMoveEvent *e)
{
    if (m_parentWidget) {
        m_parentWidget->move(pos());
    }
    if (!m_isMiniMode && !m_isMaxWindow && !m_isFullScreen)
        m_normalRect = QRect(mapToGlobal(QPoint(0,0)), QSize(width(), height()));
    return QDialog::moveEvent(e);
}

void TopWindow::mouseMoveEvent(QMouseEvent *e)
{
    if (m_isMove) {
        move(pos() + e->pos() - m_pressPos);
    }
}

void TopWindow::mousePressEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton) {
        m_pressPos = e->pos();
        m_isMove = true;
    }
    // 主界面也能右键呼出菜单
    else if (e->button() == Qt::RightButton && QGuiApplication::focusWindow()) {
        g_user_signal->showRightMenu();
    }
}

void TopWindow::mouseReleaseEvent(QMouseEvent *e)
{
    m_isMove = false;
}

void TopWindow::resizeEvent(QResizeEvent *e)
{
    resetLayout();
    return QWidget::resizeEvent(e);
}

void TopWindow::showEvent(QShowEvent *event)
{
    if (!m_isMiniMode) {
        m_parentWidget->setGeometry(m_normalRect);
        setGeometry(m_normalRect);
    }
    m_playListWidget->move(width()-16, 0);
    return QWidget::showEvent(event);
}

void TopWindow::hideEvent(QHideEvent *event)
{
    return QDialog::hideEvent(event);
}

void TopWindow::leaveEvent(QEvent *event)
{
    if (isActiveWindow() &&
            (QCursor::pos().x() > m_parentWidget->pos().x() + width() ||
             QCursor::pos().y() > m_parentWidget->pos().y() + height() ||
             QCursor::pos().x() < m_parentWidget->pos().x() ||
             QCursor::pos().y() < m_parentWidget->pos().y())) {
        m_parentWidget->activateWindow();
    }
    return QDialog::leaveEvent(event);
}

void TopWindow::enterEvent(QEvent *event)
{
    hideAll(false);
    if (m_parentWidget->isActiveWindow()) {
        activateWindow();
    }
    return QDialog::enterEvent(event);
}

void TopWindow::keyPressEvent(QKeyEvent *event)
{
    // 按 esc 退出全屏
    if (event->key() == Qt::Key_Escape) {
        if(isFullScreen())
            g_user_signal->fullScreen();
    }
    else if (event->key() == Qt::Key_F1) {
        openHelpDoc();
    }
}

void TopWindow::dragEnterEvent(QDragEnterEvent *event)
{
    event->acceptProposedAction();
}

void TopWindow::dropEvent(QDropEvent *event)
{
    QList<QUrl> listUrl = event->mimeData()->urls();
    QStringList filelist;
    Extensions e;
    QRegExp rx_video(e.video().forRegExp());
    QRegExp rx_audio(e.audio().forRegExp());
    rx_video.setCaseSensitivity(Qt::CaseInsensitive);
    rx_audio.setCaseSensitivity(Qt::CaseInsensitive);
    for(QUrl url : listUrl)
    {
        QString path = url.path();

        // 不要 file:// 前缀只要绝对路径
        if(path.startsWith("file:"))
            path.remove(0, 7);

        // 拖入文件需要做类型判断
        QFileInfo fi(path);
        if (fi.isDir()) {
            // 如果是文件夹的话添加文件夹
            g_user_signal->addDir(path);
        }
        else if (rx_video.indexIn(fi.suffix()) > -1 || rx_audio.indexIn(fi.suffix()) > -1) {
            filelist << path;
        }
    }
    if(filelist.count() == 0)
        return;
    g_user_signal->addFiles(filelist);
}
