# Copyright (c) 2015, JINGROW and Contributors
# License: MIT. See LICENSE

import jingrow
import jingrow.utils
from jingrow import _
from jingrow.model import log_types
from jingrow.query_builder import PageType
from jingrow.utils import get_url_to_form


@jingrow.whitelist()
def update_follow(pagetype: str, pg_name: str, following: bool):
	if following:
		return follow_document(pagetype, pg_name, jingrow.session.user)
	else:
		return unfollow_document(pagetype, pg_name, jingrow.session.user)


@jingrow.whitelist()
def follow_document(pagetype, pg_name, user):
	"""
	param:
	Pagetype name
	pg name
	user email

	condition:
	avoided for some pagetype
	follow only if track changes are set to 1
	"""
	if (
		pagetype
		in (
			"Communication",
			"ToDo",
			"Email Unsubscribe",
			"File",
			"Comment",
			"Email Account",
			"Email Domain",
		)
		or pagetype in log_types
	):
		return

	if (not jingrow.get_meta(pagetype).track_changes) or user == "Administrator":
		return

	if not jingrow.db.get_value("User", user, "document_follow_notify", ignore=True, cache=True):
		return

	if not is_document_followed(pagetype, pg_name, user):
		pg = jingrow.new_pg("Page Follow")
		pg.update({"ref_pagetype": pagetype, "ref_pagename": pg_name, "user": user})
		pg.save()
		return pg


@jingrow.whitelist()
def unfollow_document(pagetype, pg_name, user):
	pg = jingrow.get_all(
		"Page Follow",
		filters={"ref_pagetype": pagetype, "ref_pagename": pg_name, "user": user},
		fields=["name"],
		limit=1,
	)
	if pg:
		jingrow.delete_pg("Page Follow", pg[0].name)
		return 1
	return 0


def get_message(pg_name, pagetype, frequency, user):
	activity_list = get_version(pagetype, pg_name, frequency, user) + get_comments(
		pagetype, pg_name, frequency, user
	)
	return sorted(activity_list, key=lambda k: k["time"], reverse=True)


def send_email_alert(receiver, pageinfo, timeline):
	if receiver:
		jingrow.sendmail(
			subject=_("Page Follow Notification"),
			recipients=[receiver],
			template="document_follow",
			args={
				"pageinfo": pageinfo,
				"timeline": timeline,
			},
		)


def send_document_follow_mails(frequency):
	"""
	param:
	frequency for sanding mails

	task:
	set receiver according to frequency
	group document list according to user
	get changes, activity, comments on pagetype
	call method to send mail
	"""

	user_list = get_user_list(frequency)

	for user in user_list:
		message, valid_document_follows = get_message_for_user(frequency, user)
		if message:
			send_email_alert(user, valid_document_follows, message)
			# send an email if we have already spent resources creating	the message
			# nosemgrep
			jingrow.db.commit()


def get_user_list(frequency):
	PageFollow = PageType("Page Follow")
	User = PageType("User")
	return (
		jingrow.qb.from_(PageFollow)
		.join(User)
		.on(PageFollow.user == User.name)
		.where(User.document_follow_notify == 1)
		.where(User.document_follow_frequency == frequency)
		.select(PageFollow.user)
		.groupby(PageFollow.user)
	).run(pluck="user")


def get_message_for_user(frequency, user):
	message = []
	latest_document_follows = get_document_followed_by_user(user)
	valid_document_follows = []

	for document_follow in latest_document_follows:
		content = get_message(document_follow.ref_pagename, document_follow.ref_pagetype, frequency, user)
		if content:
			message = message + content
			valid_document_follows.append(
				{
					"reference_pagename": document_follow.ref_pagename,
					"reference_pagetype": document_follow.ref_pagetype,
					"reference_url": get_url_to_form(
						document_follow.ref_pagetype, document_follow.ref_pagename
					),
				}
			)
	return message, valid_document_follows


def get_document_followed_by_user(user):
	PageFollow = PageType("Page Follow")
	# at max 20 documents are sent for each user
	return (
		jingrow.qb.from_(PageFollow)
		.where(PageFollow.user == user)
		.select(PageFollow.ref_pagetype, PageFollow.ref_pagename)
		.orderby(PageFollow.modified)
		.limit(20)
	).run(as_dict=True)


def get_version(pagetype, pg_name, frequency, user):
	timeline = []
	version = jingrow.get_all(
		"Version",
		filters=[
			["ref_pagetype", "=", pagetype],
			["pagename", "=", pg_name],
			*_get_filters(frequency, user),
		],
		fields=["data", "modified", "modified_by"],
	)
	if version:
		for v in version:
			change = jingrow.parse_json(v.data)
			time = jingrow.utils.format_datetime(v.modified, "hh:mm a")
			timeline_items = []
			if change.changed:
				timeline_items = get_field_changed(change.changed, time, pagetype, pg_name, v)
			if change.row_changed:
				timeline_items = get_row_changed(change.row_changed, time, pagetype, pg_name, v)
			if change.added:
				timeline_items = get_added_row(change.added, time, pagetype, pg_name, v)

			timeline = timeline + timeline_items

	return timeline


def get_comments(pagetype, pg_name, frequency, user):
	from jingrow.core.utils import html2text

	timeline = []
	comments = jingrow.get_all(
		"Comment",
		filters=[
			["reference_pagetype", "=", pagetype],
			["reference_name", "=", pg_name],
			*_get_filters(frequency, user),
		],
		fields=["content", "modified", "modified_by", "comment_type"],
	)
	for comment in comments:
		if comment.comment_type == "Like":
			by = f""" By : <b>{comment.modified_by}<b>"""
		elif comment.comment_type == "Comment":
			by = f"""Commented by : <b>{comment.modified_by}<b>"""
		else:
			by = ""

		time = jingrow.utils.format_datetime(comment.modified, "hh:mm a")
		timeline.append(
			{
				"time": comment.modified,
				"data": {"time": time, "comment": html2text(str(comment.content)), "by": by},
				"pagetype": pagetype,
				"pg_name": pg_name,
				"type": "comment",
			}
		)
	return timeline


def is_document_followed(pagetype, pg_name, user):
	return jingrow.db.exists(
		"Page Follow", {"ref_pagetype": pagetype, "ref_pagename": pg_name, "user": user}
	)


@jingrow.whitelist()
def get_follow_users(pagetype, pg_name):
	return jingrow.get_all(
		"Page Follow", filters={"ref_pagetype": pagetype, "ref_pagename": pg_name}, fields=["user"]
	)


def get_row_changed(row_changed, time, pagetype, pg_name, v):
	from jingrow.core.utils import html2text

	items = []
	for d in row_changed:
		d[2] = d[2] if d[2] else " "
		d[0] = d[0] if d[0] else " "
		d[3][0][1] = d[3][0][1] if d[3][0][1] else " "
		items.append(
			{
				"time": v.modified,
				"data": {
					"time": time,
					"table_field": d[0],
					"row": str(d[1]),
					"field": d[3][0][0],
					"from": html2text(str(d[3][0][1])),
					"to": html2text(str(d[3][0][2])),
				},
				"pagetype": pagetype,
				"pg_name": pg_name,
				"type": "row changed",
				"by": v.modified_by,
			}
		)
	return items


def get_added_row(added, time, pagetype, pg_name, v):
	return [
		{
			"time": v.modified,
			"data": {"to": d[0], "time": time},
			"pagetype": pagetype,
			"pg_name": pg_name,
			"type": "row added",
			"by": v.modified_by,
		}
		for d in added
	]


def get_field_changed(changed, time, pagetype, pg_name, v):
	from jingrow.core.utils import html2text

	items = []
	for d in changed:
		d[1] = d[1] if d[1] else " "
		d[2] = d[2] if d[2] else " "
		d[0] = d[0] if d[0] else " "
		items.append(
			{
				"time": v.modified,
				"data": {
					"time": time,
					"field": d[0],
					"from": html2text(str(d[1])),
					"to": html2text(str(d[2])),
				},
				"pagetype": pagetype,
				"pg_name": pg_name,
				"type": "field changed",
				"by": v.modified_by,
			}
		)
	return items


def send_hourly_updates():
	send_document_follow_mails("Hourly")


def send_daily_updates():
	send_document_follow_mails("Daily")


def send_weekly_updates():
	send_document_follow_mails("Weekly")


def _get_filters(frequency, user):
	filters = [
		["modified_by", "!=", user],
	]

	if frequency == "Weekly":
		filters += [
			["modified", ">", jingrow.utils.add_days(jingrow.utils.nowdate(), -7)],
			["modified", "<", jingrow.utils.nowdate()],
		]

	elif frequency == "Daily":
		filters += [
			["modified", ">", jingrow.utils.add_days(jingrow.utils.nowdate(), -1)],
			["modified", "<", jingrow.utils.nowdate()],
		]

	elif frequency == "Hourly":
		filters += [
			["modified", ">", jingrow.utils.add_to_date(jingrow.utils.now_datetime(), hours=-1)],
			["modified", "<", jingrow.utils.now_datetime()],
		]

	return filters
