// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2009 Konrad Twardowski

#include "idlemonitor.h"

#include "../utils.h"

#ifdef Q_OS_WIN32
	#ifndef WIN32_LEAN_AND_MEAN
		#define WIN32_LEAN_AND_MEAN
	#endif // WIN32_LEAN_AND_MEAN
	#include <windows.h>
#else
	#include "../actions/lock.h"
#endif // Q_OS_WIN32

#include <QDebug>

#ifdef KS_KF5
	#include <KIdleTime>
#endif // KS_KF5

// public

IdleMonitor::IdleMonitor()
	: DateTimeTriggerBase(
		i18n("On User Inactivity (HH:MM)"),
// TODO: better icon - user-idle?
		"user-away-extended",
		"idle-monitor"
	)
{
	setCanBookmark(true);

// TODO: first/initial interval should be smaller
	setCheckInterval(5s);
// TEST: setCheckInterval(1s);

	#if defined(KS_KF5) || defined(Q_OS_WIN32)
	m_supported = true;
	#elif defined(Q_OS_HAIKU)
	m_supported = false;
	#elif defined(QT_DBUS_LIB)
// FIXME: returns invalid time on KDE (known bug)
	m_supported = LockAction::getQDBusInterface()->isValid() && !Utils::isKDE();

	// HACK: Check if it's actually implemented... (GNOME Shell)
	if (m_supported) {
		QDBusReply<quint32> reply = LockAction::getQDBusInterface()->call("GetSessionIdleTime");
		if (!reply.isValid()) {
			qDebug() << "GetSessionIdleTime not implemented";
			m_supported = false;
		}
	}
	#else
	m_supported = false;
	#endif

	setToolTip(i18n("Use this trigger to detect user inactivity\n(example: no mouse clicks)."));
}

bool IdleMonitor::canActivateAction() {
	auto idleTime = getSessionIdleTime();
	
	if (idleTime == 0s) {
		setInfoStatus(
			i18n("Remaining time: %0")
				.arg("${BEGIN:b}" + i18n("Unknown") + "${END:b}")
		);

// FIXME: repaint
		updateProgressWidgets(0s, 0s);

		return false;
	}

	seconds maximumIdleTime = Utils::toSeconds(getSelectedTime());
	//qDebug() << "maximumIdleTime=" << maximumIdleTime;
	
	if (idleTime >= maximumIdleTime)
		return true;

	seconds secsTo = maximumIdleTime - idleTime;

// TODO: review "hh:mm[:ss]" formats
	setInfoStatus(
		i18n("Remaining time: %0")
			.arg("${BEGIN:b}~" + formatSecsTo(secsTo) + "${END:b}")
	);

	updateProgressWidgets(secsTo, maximumIdleTime);

	return false;
}

QString IdleMonitor::getStringOption() {
	return getSelectedTime().toString(TIME_PARSE_FORMAT);
}

void IdleMonitor::setStringOption(const QString &option) {
// FIXME: use "C" locale in QDate/QTime fromString/toString
	QTime time = QTime::fromString(option, TIME_PARSE_FORMAT);
	setSelectedTime(time);
}

void IdleMonitor::initDateTimeWidget(QDateTimeEdit *dateTimeEdit) {
	dateTimeEdit->setDisplayFormat(TIME_DISPLAY_FORMAT);
	dateTimeEdit->setLocale(QLocale::c());
	dateTimeEdit->setMinimumTime(QTime(0, 1));
	dateTimeEdit->setToolTip(i18n("Enter a maximum user inactivity in \"HH:MM\" format (Hours:Minutes)"));
}

void IdleMonitor::setState(const State state) {
	if (state == State::Start) {
#ifdef KS_KF5
		KIdleTime::instance()->simulateUserActivity();
#else
		#ifdef QT_DBUS_LIB
		if (m_supported)
			LockAction::getQDBusInterface()->call("SimulateUserActivity");
		#endif // QT_DBUS_LIB
#endif // KS_KF5

		// reset
		updateProgressWidgets(0s, 0s);
	}
	else if (state == State::Stop) {
// TODO: review (global)
		setInfoStatus("");
	}
}

// protected

void IdleMonitor::updateStatus() {
	setInfoStatus("");
}

// private

seconds IdleMonitor::getSessionIdleTime() {
	if (!m_supported)
		return 0s;

#ifdef Q_OS_WIN32
	LASTINPUTINFO lii;
	lii.cbSize = sizeof(LASTINPUTINFO);
	BOOL result = ::GetLastInputInfo(&lii);
	if (result) {
		qint64 tickCount = ::GetTickCount();
		qint64 lastTick = lii.dwTime;

		return duration_cast<seconds>(milliseconds(tickCount - lastTick));
	}
#elif defined(KS_KF5)
	return duration_cast<seconds>(milliseconds(KIdleTime::instance()->idleTime()));
#elif defined(QT_DBUS_LIB)
	QDBusReply<quint32> reply = LockAction::getQDBusInterface()->call("GetSessionIdleTime");
	if (reply.isValid()) {
		//qDebug() << "org.freedesktop.ScreenSaver: reply=" << reply.value();

		return seconds(reply.value());
	}
#endif // Q_OS_WIN32

	return 0s;
}
