# Copyright (c) 2018, JINGROW and Contributors
# License: MIT. See LICENSE
from typing import TYPE_CHECKING

import jingrow
from jingrow.automation.pagetype.auto_repeat.auto_repeat import (
	create_repeated_entries,
	get_auto_repeat_entries,
	week_map,
)
from jingrow.custom.pagetype.custom_field.custom_field import create_custom_field
from jingrow.tests.utils import JingrowTestCase
from jingrow.utils import add_days, add_months, getdate, today

if TYPE_CHECKING:
	from jingrow.custom.pagetype.custom_field.custom_field import CustomField


def add_custom_fields() -> "CustomField":
	df = dict(
		fieldname="auto_repeat",
		label="Auto Repeat",
		fieldtype="Link",
		insert_after="sender",
		options="Auto Repeat",
		hidden=1,
		print_hide=1,
		read_only=1,
	)
	return create_custom_field("ToDo", df) or jingrow.get_pg(
		"Custom Field", dict(fieldname=df["fieldname"], dt="ToDo")
	)


class TestAutoRepeat(JingrowTestCase):
	@classmethod
	def setUpClass(cls):
		cls.custom_field = add_custom_fields()
		cls.addClassCleanup(cls.custom_field.delete)
		return super().setUpClass()

	def test_daily_auto_repeat(self):
		todo = jingrow.get_pg(
			dict(pagetype="ToDo", description="test recurring todo", assigned_by="Administrator")
		).insert()

		pg = make_auto_repeat(reference_document=todo.name)
		self.assertEqual(pg.next_schedule_date, today())
		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)
		jingrow.db.commit()

		todo = jingrow.get_pg(pg.reference_pagetype, pg.reference_document)
		self.assertEqual(todo.auto_repeat, pg.name)

		new_todo = jingrow.db.get_value("ToDo", {"auto_repeat": pg.name, "name": ("!=", todo.name)}, "name")

		new_todo = jingrow.get_pg("ToDo", new_todo)

		self.assertEqual(todo.get("description"), new_todo.get("description"))

	def test_weekly_auto_repeat(self):
		todo = jingrow.get_pg(
			dict(pagetype="ToDo", description="test weekly todo", assigned_by="Administrator")
		).insert()

		pg = make_auto_repeat(
			reference_pagetype="ToDo",
			frequency="Weekly",
			reference_document=todo.name,
			start_date=add_days(today(), -7),
		)

		self.assertEqual(pg.next_schedule_date, today())
		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)
		jingrow.db.commit()

		todo = jingrow.get_pg(pg.reference_pagetype, pg.reference_document)
		self.assertEqual(todo.auto_repeat, pg.name)

		new_todo = jingrow.db.get_value("ToDo", {"auto_repeat": pg.name, "name": ("!=", todo.name)}, "name")

		new_todo = jingrow.get_pg("ToDo", new_todo)

		self.assertEqual(todo.get("description"), new_todo.get("description"))

	def test_weekly_auto_repeat_with_weekdays(self):
		todo = jingrow.get_pg(
			dict(pagetype="ToDo", description="test auto repeat with weekdays", assigned_by="Administrator")
		).insert()

		weekdays = list(week_map.keys())
		current_weekday = getdate().weekday()
		days = [{"day": weekdays[current_weekday]}, {"day": weekdays[(current_weekday + 2) % 7]}]
		pg = make_auto_repeat(
			reference_pagetype="ToDo",
			frequency="Weekly",
			reference_document=todo.name,
			start_date=add_days(today(), -7),
			days=days,
		)

		self.assertEqual(pg.next_schedule_date, today())
		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)
		jingrow.db.commit()

		todo = jingrow.get_pg(pg.reference_pagetype, pg.reference_document)
		self.assertEqual(todo.auto_repeat, pg.name)

		pg.reload()
		self.assertEqual(pg.next_schedule_date, add_days(getdate(), 2))

	def test_monthly_auto_repeat(self):
		start_date = today()
		end_date = add_months(start_date, 12)

		todo = jingrow.get_pg(
			dict(pagetype="ToDo", description="test recurring todo", assigned_by="Administrator")
		).insert()

		self.monthly_auto_repeat("ToDo", todo.name, start_date, end_date)
		# test without end_date
		todo = jingrow.get_pg(
			dict(
				pagetype="ToDo",
				description="test recurring todo without end_date",
				assigned_by="Administrator",
			)
		).insert()
		self.monthly_auto_repeat("ToDo", todo.name, start_date)

	def monthly_auto_repeat(self, pagetype, pagename, start_date, end_date=None):
		def get_months(start, end):
			diff = (12 * end.year + end.month) - (12 * start.year + start.month)
			return diff + 1

		pg = make_auto_repeat(
			reference_pagetype=pagetype,
			frequency="Monthly",
			reference_document=pagename,
			start_date=start_date,
			end_date=end_date,
		)

		pg.disable_auto_repeat()

		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)
		pagenames = jingrow.get_all(pg.reference_pagetype, {"auto_repeat": pg.name})
		self.assertEqual(len(pagenames), 1)

		pg = jingrow.get_pg("Auto Repeat", pg.name)
		pg.db_set("disabled", 0)

		months = get_months(getdate(start_date), getdate(today()))
		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)

		pagenames = jingrow.get_all(pg.reference_pagetype, {"auto_repeat": pg.name})
		self.assertEqual(len(pagenames), months)

	def test_email_notification(self):
		todo = jingrow.get_pg(
			dict(
				pagetype="ToDo",
				description="Test recurring notification attachment",
				assigned_by="Administrator",
			)
		).insert()

		pg = make_auto_repeat(
			reference_document=todo.name,
			notify=1,
			recipients="test@domain.com",
			subject="New ToDo",
			message="A new ToDo has just been created for you",
		)
		data = get_auto_repeat_entries(getdate(today()))
		create_repeated_entries(data)
		jingrow.db.commit()

		new_todo = jingrow.db.get_value("ToDo", {"auto_repeat": pg.name, "name": ("!=", todo.name)}, "name")

		email_queue = jingrow.db.exists("Email Queue", dict(reference_pagetype="ToDo", reference_name=new_todo))
		self.assertTrue(email_queue)

	def test_next_schedule_date(self):
		current_date = getdate(today())
		todo = jingrow.get_pg(
			dict(
				pagetype="ToDo", description="test next schedule date for monthly", assigned_by="Administrator"
			)
		).insert()
		pg = make_auto_repeat(
			frequency="Monthly", reference_document=todo.name, start_date=add_months(today(), -2)
		)

		# next_schedule_date is set as on or after current date
		# it should not be a previous month's date
		self.assertTrue(pg.next_schedule_date >= current_date)

		todo = jingrow.get_pg(
			dict(pagetype="ToDo", description="test next schedule date for daily", assigned_by="Administrator")
		).insert()
		pg = make_auto_repeat(
			frequency="Daily", reference_document=todo.name, start_date=add_days(today(), -2)
		)
		self.assertEqual(getdate(pg.next_schedule_date), current_date)

	def test_submit_on_creation(self):
		pagetype = "Test Submittable PageType"
		create_submittable_pagetype(pagetype)

		current_date = getdate()
		submittable_pg = jingrow.get_pg(dict(pagetype=pagetype, test="test submit on creation")).insert()
		submittable_pg.submit()
		pg = make_auto_repeat(
			frequency="Daily",
			reference_pagetype=pagetype,
			reference_document=submittable_pg.name,
			start_date=add_days(current_date, -1),
			submit_on_creation=1,
		)

		data = get_auto_repeat_entries(current_date)
		create_repeated_entries(data)
		pagenames = jingrow.get_all(
			pg.reference_pagetype, filters={"auto_repeat": pg.name}, fields=["pagestatus"], limit=1
		)
		self.assertEqual(pagenames[0].pagestatus, 1)


def make_auto_repeat(**args):
	args = jingrow._dict(args)
	return jingrow.get_pg(
		{
			"pagetype": "Auto Repeat",
			"reference_pagetype": args.reference_pagetype or "ToDo",
			"reference_document": args.reference_document or jingrow.db.get_value("ToDo", "name"),
			"submit_on_creation": args.submit_on_creation or 0,
			"frequency": args.frequency or "Daily",
			"start_date": args.start_date or add_days(today(), -1),
			"end_date": args.end_date or "",
			"notify_by_email": args.notify or 0,
			"recipients": args.recipients or "",
			"subject": args.subject or "",
			"message": args.message or "",
			"repeat_on_days": args.days or [],
		}
	).insert(ignore_permissions=True)


def create_submittable_pagetype(pagetype, submit_perms=1):
	if jingrow.db.exists("PageType", pagetype):
		return
	else:
		pg = jingrow.get_pg(
			{
				"pagetype": "PageType",
				"__newname": pagetype,
				"module": "Custom",
				"custom": 1,
				"is_submittable": 1,
				"fields": [{"fieldname": "test", "label": "Test", "fieldtype": "Data"}],
				"permissions": [
					{
						"role": "System Manager",
						"read": 1,
						"write": 1,
						"create": 1,
						"delete": 1,
						"submit": submit_perms,
						"cancel": submit_perms,
						"amend": submit_perms,
					}
				],
			}
		).insert()

		pg.allow_auto_repeat = 1
		pg.save()
