import os
import time
from unittest import TestCase
from unittest.mock import patch

import xhiveframework
from xhiveframework.core.doctype.scheduled_job_type.scheduled_job_type import ScheduledJobType, sync_jobs
from xhiveframework.utils import add_days, get_datetime
from xhiveframework.utils.doctor import purge_pending_jobs
from xhiveframework.utils.scheduler import (
	_get_last_modified_timestamp,
	enqueue_events,
	is_dormant,
	schedule_jobs_based_on_activity,
)


def test_timeout_10():
	time.sleep(10)


def test_method():
	pass


class TestScheduler(TestCase):
	def setUp(self):
		xhiveframework.db.rollback()

		if not os.environ.get("CI"):
			return

		purge_pending_jobs()
		if not xhiveframework.get_all("Scheduled Job Type", limit=1):
			sync_jobs()

	def tearDown(self):
		purge_pending_jobs()

	def test_enqueue_jobs(self):
		xhiveframework.db.sql("update `tabScheduled Job Type` set last_execution = '2010-01-01 00:00:00'")

		enqueued_jobs = enqueue_events(site=xhiveframework.local.site)

		self.assertIn("xhiveframework.desk.notifications.clear_notifications", enqueued_jobs)
		self.assertIn("xhiveframework.utils.change_log.check_for_update", enqueued_jobs)
		self.assertIn(
			"xhiveframework.email.doctype.auto_email_report.auto_email_report.send_monthly",
			enqueued_jobs,
		)

	def test_queue_peeking(self):
		job = get_test_job()

		with patch.object(job, "is_job_in_queue", return_value=True):
			# 1st job is in the queue (or running), don't enqueue it again
			self.assertFalse(job.enqueue())

	def test_is_dormant(self):
		self.assertTrue(is_dormant(check_time=get_datetime("2100-01-01 00:00:00")))
		self.assertTrue(is_dormant(check_time=add_days(xhiveframework.db.get_last_created("Activity Log"), 5)))
		self.assertFalse(is_dormant(check_time=xhiveframework.db.get_last_created("Activity Log")))

	def test_once_a_day_for_dormant(self):
		xhiveframework.db.truncate("Scheduled Job Log")
		self.assertTrue(schedule_jobs_based_on_activity(check_time=get_datetime("2100-01-01 00:00:00")))
		self.assertTrue(
			schedule_jobs_based_on_activity(
				check_time=add_days(xhiveframework.db.get_last_created("Activity Log"), 5)
			)
		)

		# create a fake job executed 5 days from now
		job = get_test_job(method="xhiveframework.tests.test_scheduler.test_method", frequency="Daily")
		job.execute()
		job_log = xhiveframework.get_doc("Scheduled Job Log", dict(scheduled_job_type=job.name))
		job_log.db_set(
			"modified", add_days(_get_last_modified_timestamp("Activity Log"), 5), update_modified=False
		)

		# inactive site with recent job, don't run
		self.assertFalse(
			schedule_jobs_based_on_activity(
				check_time=add_days(_get_last_modified_timestamp("Activity Log"), 5)
			)
		)

		# one more day has passed
		self.assertTrue(
			schedule_jobs_based_on_activity(
				check_time=add_days(_get_last_modified_timestamp("Activity Log"), 6)
			)
		)


def get_test_job(method="xhiveframework.tests.test_scheduler.test_timeout_10", frequency="All") -> ScheduledJobType:
	if not xhiveframework.db.exists("Scheduled Job Type", dict(method=method)):
		job = xhiveframework.get_doc(
			dict(
				doctype="Scheduled Job Type",
				method=method,
				last_execution="2010-01-01 00:00:00",
				frequency=frequency,
			)
		).insert()
	else:
		job = xhiveframework.get_doc("Scheduled Job Type", dict(method=method))
		job.db_set("last_execution", "2010-01-01 00:00:00")
		job.db_set("frequency", frequency)
	xhiveframework.db.commit()

	return job
