// For license of this file, see <project-root-folder>/LICENSE.md.

#include "gui/notifications/basetoastnotification.h"

#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"

#include <chrono>

#include <QAbstractButton>
#include <QCloseEvent>
#include <QLabel>
#include <QTimerEvent>

using namespace std::chrono_literals;

BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent), m_timerId(-1) {
  setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
  setFocusPolicy(Qt::FocusPolicy::NoFocus);
  setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, false);

  setWindowFlags(
#if defined(Q_OS_MAC)
    Qt::WindowType::SubWindow |
#else
    Qt::WindowType::Tool |
#endif
    Qt::WindowType::FramelessWindowHint | Qt::WindowType::WindowStaysOnTopHint | Qt::WindowType::WindowSystemMenuHint);

  setStyleSheet(QSL("BaseToastNotification { border: 1px solid %1; }").arg(palette().windowText().color().name()));
  installEventFilter(this);

  m_timerClosingClick.setInterval(200);
  m_timerClosingClick.setSingleShot(true);

  connect(&m_timerClosingClick, &QTimer::timeout, this, &BaseToastNotification::closeNotification);
}

BaseToastNotification::~BaseToastNotification() {
  qDebugNN << LOGSEC_NOTIFICATIONS << "Destroying BaseToastNotification.";
}

void BaseToastNotification::closeNotification() {
  emit closeRequested(this, true);
}

void BaseToastNotification::reject() {
  close();
}

void BaseToastNotification::setupCloseButton(QAbstractButton* btn) {
  btn->setToolTip(tr("Close this notification"));
  btn->setIcon(qApp->icons()->fromTheme(QSL("dialog-close"), QSL("gtk-close")));

  connect(btn, &QAbstractButton::clicked, this, &BaseToastNotification::closeNotification);
}

void BaseToastNotification::setupHeading(QLabel* lbl) {
  auto fon = lbl->font();

  fon.setBold(true);
  fon.setPointSize(fon.pointSize() * 1.2);

  lbl->setFont(fon);
}

void BaseToastNotification::stopTimedClosing() {
  if (m_timerId >= 0) {
    killTimer(m_timerId);
    m_timerId = -1;

    qDebugNN << LOGSEC_NOTIFICATIONS << "Stopping timed closing for notification.";
  }
}

void BaseToastNotification::setupTimedClosing(bool want_shorter_timeout) {
  if (m_timerId < 0) {
    auto timeout_ms = qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsDuration)).toInt() * 1000;
    m_timerId = startTimer(want_shorter_timeout ? int(timeout_ms / 2) : timeout_ms);
    qDebugNN << LOGSEC_NOTIFICATIONS << "Starting timed closing for notification.";
  }
}

bool BaseToastNotification::eventFilter(QObject* watched, QEvent* event) {
  if (watched == this && event->type() == QEvent::Type::Enter) {
    qDebugNN << LOGSEC_NOTIFICATIONS << "Notification got ENTER event.";
    stopTimedClosing();
  }

  if (watched == this && event->type() == QEvent::Type::Leave) {
    qDebugNN << LOGSEC_NOTIFICATIONS << "Notification got LEAVE event.";
    setupTimedClosing(true);
  }

  if (event->type() == QEvent::Type::MouseButtonPress || event->type() == QEvent::Type::MouseButtonRelease) {
    if (dynamic_cast<QMouseEvent*>(event)->button() == Qt::MouseButton::RightButton) {
      event->accept();
      QCoreApplication::processEvents();
      m_timerClosingClick.start();
      return true;
    }
  }

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

void BaseToastNotification::closeEvent(QCloseEvent* event) {
  Q_UNUSED(event)

  qDebugNN << LOGSEC_NOTIFICATIONS << "Notification got CLOSE event.";
  stopTimedClosing();
}

void BaseToastNotification::timerEvent(QTimerEvent* event) {
  if (event->timerId() == m_timerId) {
    qDebugNN << LOGSEC_NOTIFICATIONS << "Notification got TIMER event.";
    stopTimedClosing();
    emit closeRequested(this, true);
  }
}
