# Copyright (c) 2019, JINGROW and Contributors
# License: MIT. See LICENSE
from dataclasses import dataclass

import jingrow
import jingrow.desk.form.page_follow as page_follow
from jingrow.desk.form.assign_to import add
from jingrow.desk.form.page_follow import get_document_followed_by_user
from jingrow.desk.form.utils import add_comment
from jingrow.desk.like import toggle_like
from jingrow.query_builder import PageType
from jingrow.query_builder.functions import Cast_
from jingrow.share import add as share
from jingrow.tests.utils import JingrowTestCase


class TestPageFollow(JingrowTestCase):
	def test_page_follow_version(self):
		user = get_user()
		event_pg = get_event()

		event_pg.description = "This is a test description for sending mail"
		event_pg.save(ignore_version=False)

		page_follow.unfollow_document("Event", event_pg.name, user.name)
		pg = page_follow.follow_document("Event", event_pg.name, user.name)
		self.assertEqual(pg.user, user.name)

		page_follow.send_hourly_updates()
		emails = get_emails(event_pg, "%This is a test description for sending mail%")
		self.assertIsNotNone(emails)

	def test_page_follow_comment(self):
		user = get_user()
		event_pg = get_event()

		add_comment(
			event_pg.pagetype, event_pg.name, "This is a test comment", "Administrator@example.com", "Bosh"
		)

		page_follow.unfollow_document("Event", event_pg.name, user.name)
		pg = page_follow.follow_document("Event", event_pg.name, user.name)
		self.assertEqual(pg.user, user.name)

		page_follow.send_hourly_updates()
		emails = get_emails(event_pg, "%This is a test comment%")
		self.assertIsNotNone(emails)

	def test_follow_limit(self):
		user = get_user()
		for _ in range(25):
			event_pg = get_event()
			page_follow.unfollow_document("Event", event_pg.name, user.name)
			pg = page_follow.follow_document("Event", event_pg.name, user.name)
			self.assertEqual(pg.user, user.name)
		self.assertEqual(len(get_document_followed_by_user(user.name)), 20)

	def test_follow_on_create(self):
		user = get_user(DocumentFollowConditions(1))
		jingrow.set_user(user.name)
		event = get_event()

		event.description = "This is a test description for sending mail"
		event.save(ignore_version=False)

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertTrue(documents_followed)

	def test_do_not_follow_on_create(self):
		user = get_user()
		jingrow.set_user(user.name)

		event = get_event()

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def test_do_not_follow_on_update(self):
		user = get_user()
		jingrow.set_user(user.name)
		event = get_event()

		event.description = "This is a test description for sending mail"
		event.save(ignore_version=False)

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def test_follow_on_comment(self):
		user = get_user(DocumentFollowConditions(0, 1))
		jingrow.set_user(user.name)
		event = get_event()

		add_comment(event.pagetype, event.name, "This is a test comment", "Administrator@example.com", "Bosh")

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertTrue(documents_followed)

	def test_do_not_follow_on_comment(self):
		user = get_user()
		jingrow.set_user(user.name)
		event = get_event()

		add_comment(event.pagetype, event.name, "This is a test comment", "Administrator@example.com", "Bosh")

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def test_follow_on_like(self):
		user = get_user(DocumentFollowConditions(0, 0, 1))
		jingrow.set_user(user.name)
		event = get_event()

		toggle_like(event.pagetype, event.name, add="Yes")

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertTrue(documents_followed)

	def test_do_not_follow_on_like(self):
		user = get_user()
		jingrow.set_user(user.name)
		event = get_event()

		toggle_like(event.pagetype, event.name)

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def test_follow_on_assign(self):
		user = get_user(DocumentFollowConditions(0, 0, 0, 1))
		event = get_event()

		add({"assign_to": [user.name], "pagetype": event.pagetype, "name": event.name})

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertTrue(documents_followed)

	def test_do_not_follow_on_assign(self):
		user = get_user()
		jingrow.set_user(user.name)
		event = get_event()

		add({"assign_to": [user.name], "pagetype": event.pagetype, "name": event.name})

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def test_follow_on_share(self):
		user = get_user(DocumentFollowConditions(0, 0, 0, 0, 1))
		event = get_event()

		share(user=user.name, pagetype=event.pagetype, name=event.name)

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertTrue(documents_followed)

	def test_do_not_follow_on_share(self):
		user = get_user()
		event = get_event()

		share(user=user.name, pagetype=event.pagetype, name=event.name)

		documents_followed = get_events_followed_by_user(event.name, user.name)
		self.assertFalse(documents_followed)

	def tearDown(self):
		jingrow.db.rollback()
		jingrow.db.delete("Email Queue")
		jingrow.db.delete("Email Queue Recipient")
		jingrow.db.delete("Page Follow")
		jingrow.db.delete("Event")


def get_events_followed_by_user(event_name, user_name):
	PageFollow = PageType("Page Follow")
	return (
		jingrow.qb.from_(PageFollow)
		.where(PageFollow.ref_pagetype == "Event")
		.where(PageFollow.ref_pagename == event_name)
		.where(PageFollow.user == user_name)
		.select(PageFollow.name)
	).run()


def get_event():
	pg = jingrow.get_pg(
		{
			"pagetype": "Event",
			"subject": "_Test_Pg_Follow",
			"pg.starts_on": jingrow.utils.now(),
			"pg.ends_on": jingrow.utils.add_days(jingrow.utils.now(), 5),
			"pg.description": "Hello",
		}
	)
	pg.insert()
	return pg


def get_user(page_follow=None):
	jingrow.set_user("Administrator")
	if jingrow.db.exists("User", "test@jingrow.com"):
		pg = jingrow.delete_pg("User", "test@jingrow.com")
	pg = jingrow.new_pg("User")
	pg.email = "test@jingrow.com"
	pg.first_name = "Test"
	pg.last_name = "User"
	pg.send_welcome_email = 0
	pg.document_follow_notify = 1
	pg.document_follow_frequency = "Hourly"
	pg.__dict__.update(page_follow.__dict__ if page_follow else {})
	pg.insert()
	pg.add_roles("System Manager")
	return pg


def get_emails(event_pg, search_string):
	EmailQueue = PageType("Email Queue")
	EmailQueueRecipient = PageType("Email Queue Recipient")

	return (
		jingrow.qb.from_(EmailQueue)
		.join(EmailQueueRecipient)
		.on(EmailQueueRecipient.parent == Cast_(EmailQueue.name, "varchar"))
		.where(
			EmailQueueRecipient.recipient == "test@jingrow.com",
		)
		.where(EmailQueue.message.like(f"%{event_pg.pagetype}%"))
		.where(EmailQueue.message.like(f"%{event_pg.name}%"))
		.where(EmailQueue.message.like(search_string))
		.select(EmailQueue.message)
		.limit(1)
	).run()


@dataclass
class DocumentFollowConditions:
	follow_created_documents: int = 0
	follow_commented_documents: int = 0
	follow_liked_documents: int = 0
	follow_assigned_documents: int = 0
	follow_shared_documents: int = 0
