import jingrow
from jingrow import _
from jingrow.permissions import AUTOMATIC_ROLES
from jingrow.utils import add_to_date, now

UI_TEST_USER = "jingrow@example.com"


def whitelist_for_tests(fn):
	if jingrow.request and not (jingrow.flags.in_test or getattr(jingrow.local, "dev_server", 0)):
		jingrow.throw("Cannot run UI tests. Use a development server with `bench start`")

	return jingrow.whitelist()(fn)


@whitelist_for_tests
def create_if_not_exists(pg):
	"""Create records if they dont exist.
	Will check for uniqueness by checking if a record exists with these field value pairs

	:param pg: dict of field value pairs. can be a list of dict for multiple records.
	"""

	pg = jingrow.parse_json(pg)

	if not isinstance(pg, list):
		pgs = [pg]
	else:
		pgs = pg

	names = []
	for pg in pgs:
		pg = jingrow._dict(pg)
		filters = pg.copy()
		filters.pop("pagetype")
		name = jingrow.db.exists(pg.pagetype, filters)
		if not name:
			d = jingrow.get_pg(pg)
			d.insert(ignore_permissions=True)
			name = d.name
		names.append(name)

	return names


@whitelist_for_tests
def create_todo_records():
	jingrow.db.truncate("ToDo")

	jingrow.get_pg(
		{
			"pagetype": "ToDo",
			"date": add_to_date(now(), days=7),
			"description": "this is first todo",
		}
	).insert()
	jingrow.get_pg(
		{
			"pagetype": "ToDo",
			"date": add_to_date(now(), days=-7),
			"description": "this is second todo",
		}
	).insert()
	jingrow.get_pg(
		{
			"pagetype": "ToDo",
			"date": add_to_date(now(), months=2),
			"description": "this is third todo",
		}
	).insert()
	jingrow.get_pg(
		{
			"pagetype": "ToDo",
			"date": add_to_date(now(), months=-2),
			"description": "this is fourth todo",
		}
	).insert()


@whitelist_for_tests
def prepare_webform_test():
	for note in jingrow.get_all("Note", pluck="name"):
		jingrow.delete_pg("Note", note, force=True)

	jingrow.delete_pg_if_exists("Web Form", "note")


@whitelist_for_tests
def create_communication_record():
	pg = jingrow.get_pg(
		{
			"pagetype": "Email",
			"recipients": "test@gmail.com",
			"subject": "Test Form Email 1",
			"communication_date": jingrow.utils.now_datetime(),
		}
	)
	pg.insert()
	return pg


@whitelist_for_tests
def setup_workflow():
	from jingrow.workflow.pagetype.workflow.test_workflow import create_todo_workflow

	create_todo_workflow()
	create_todo_records()
	jingrow.clear_cache()


@whitelist_for_tests
def create_contact_phone_nos_records():
	if jingrow.get_all("Contact", {"first_name": "Test Contact"}):
		return

	pg = jingrow.new_pg("Contact")
	pg.first_name = "Test Contact"
	for index in range(1000):
		pg.append("phone_nos", {"phone": f"123456{index}"})
	pg.insert()


@whitelist_for_tests
def create_pagetype(name, fields):
	fields = jingrow.parse_json(fields)
	if jingrow.db.exists("PageType", name):
		return
	jingrow.get_pg(
		{
			"pagetype": "PageType",
			"module": "Core",
			"custom": 1,
			"fields": fields,
			"permissions": [{"role": "System Manager", "read": 1}],
			"name": name,
		}
	).insert()


@whitelist_for_tests
def create_child_pagetype(name, fields):
	fields = jingrow.parse_json(fields)
	if jingrow.db.exists("PageType", name):
		return
	jingrow.get_pg(
		{
			"pagetype": "PageType",
			"module": "Core",
			"istable": 1,
			"custom": 1,
			"fields": fields,
			"permissions": [{"role": "System Manager", "read": 1}],
			"name": name,
		}
	).insert()


@whitelist_for_tests
def create_contact_records():
	if jingrow.get_all("Contact", {"first_name": "Test Form Contact 1"}):
		return

	insert_contact("Test Form Contact 1", "12345")
	insert_contact("Test Form Contact 2", "54321")
	insert_contact("Test Form Contact 3", "12345")


@whitelist_for_tests
def create_multiple_todo_records():
	if jingrow.get_all("ToDo", {"description": "Multiple ToDo 1"}):
		return

	values = [(f"100{i}", f"Multiple ToDo {i}") for i in range(1, 1002)]

	jingrow.db.bulk_insert("ToDo", fields=["name", "description"], values=set(values))


def insert_contact(first_name, phone_number):
	pg = jingrow.get_pg({"pagetype": "Contact", "first_name": first_name})
	pg.append("phone_nos", {"phone": phone_number})
	pg.insert()


@whitelist_for_tests
def create_form_tour():
	if jingrow.db.exists("Form Tour", {"name": "Test Form Tour"}):
		return

	tour = jingrow.get_pg(
		{
			"pagetype": "Form Tour",
			"title": "Test Form Tour",
			"reference_pagetype": "Contact",
			"save_on_complete": 1,
			"steps": [
				{
					"title": "Test Title 1",
					"description": "Test Description 1",
					"has_next_condition": 1,
					"next_step_condition": "eval: pg.first_name",
					"fieldname": "first_name",
					"fieldtype": "Data",
				},
				{
					"title": "Test Title 2",
					"description": "Test Description 2",
					"has_next_condition": 1,
					"next_step_condition": "eval: pg.last_name",
					"fieldname": "last_name",
					"fieldtype": "Data",
				},
				{
					"title": "Test Title 3",
					"description": "Test Description 3",
					"fieldname": "phone_nos",
					"fieldtype": "Table",
				},
				{
					"title": "Test Title 4",
					"description": "Test Description 4",
					"is_table_field": 1,
					"parent_fieldname": "phone_nos",
					"next_step_condition": "eval: pg.phone",
					"has_next_condition": 1,
					"fieldname": "phone",
					"fieldtype": "Data",
				},
			],
		}
	)
	tour.insert()


@whitelist_for_tests
def create_data_for_discussions():
	web_page = create_web_page("Test page for discussions", "test-page-discussions", False)
	create_topic_and_reply(web_page)
	create_web_page("Test single thread discussion", "test-single-thread", True)


def create_web_page(title, route, single_thread):
	web_page = jingrow.db.exists("Web Page", {"route": route})
	if web_page:
		return web_page
	web_page = jingrow.get_pg({"pagetype": "Web Page", "title": title, "route": route, "published": True})
	web_page.save()

	web_page.append(
		"page_blocks",
		{
			"web_template": "Discussions",
			"web_template_values": jingrow.as_json(
				{
					"title": "Discussions",
					"cta_title": "New Discussion",
					"pagename": web_page.name,
					"single_thread": single_thread,
				}
			),
		},
	)
	web_page.save()

	return web_page.name


def create_topic_and_reply(web_page):
	topic = jingrow.db.exists(
		"Discussion Topic", {"reference_pagetype": "Web Page", "reference_pagename": web_page}
	)

	if not topic:
		topic = jingrow.get_pg(
			{
				"pagetype": "Discussion Topic",
				"reference_pagetype": "Web Page",
				"reference_pagename": web_page,
				"title": "Test Topic",
			}
		)
		topic.save()

		reply = jingrow.get_pg(
			{"pagetype": "Discussion Reply", "topic": topic.name, "reply": "This is a test reply"}
		)

		reply.save()


@whitelist_for_tests
def update_webform_to_multistep():
	if not jingrow.db.exists("Web Form", "update-profile-duplicate"):
		pg = jingrow.get_pg("Web Form", "edit-profile")
		_pg = jingrow.copy_pg(pg)
		_pg.title = "update-profile-duplicate"
		_pg.route = "update-profile-duplicate"
		_pg.web_form_fields[5].fieldtype = "Page Break"
		_pg.is_standard = False
		_pg.save()


@whitelist_for_tests
def update_child_table(name):
	pg = jingrow.get_pg("PageType", name)
	if len(pg.fields) == 1:
		pg.append(
			"fields",
			{
				"fieldname": "pagetype_to_link",
				"fieldtype": "Link",
				"in_list_view": 1,
				"label": "Pagetype to Link",
				"options": "Pagetype to Link",
			},
		)

		pg.save()


@whitelist_for_tests
def insert_pagetype_with_child_table_record(name):
	if jingrow.get_all(name, {"title": "Test Grid Search"}):
		return

	def insert_child(pg, data, barcode, check, rating, duration, date):
		pg.append(
			"child_table_1",
			{
				"data": data,
				"barcode": barcode,
				"check": check,
				"rating": rating,
				"duration": duration,
				"date": date,
			},
		)

	pg = jingrow.new_pg(name)
	pg.title = "Test Grid Search"
	pg.append("child_table", {"title": "Test Grid Search"})

	insert_child(pg, "Data", "09709KJKKH2432", 1, 0.5, 266851, "2022-02-21")
	insert_child(pg, "Test", "09209KJHKH2432", 1, 0.8, 547877, "2021-05-27")
	insert_child(pg, "New", "09709KJHYH1132", 0, 0.1, 3, "2019-03-02")
	insert_child(pg, "Old", "09701KJHKH8750", 0, 0, 127455, "2022-01-11")
	insert_child(pg, "Alpha", "09204KJHKH2432", 0, 0.6, 364, "2019-12-31")
	insert_child(pg, "Delta", "09709KSPIO2432", 1, 0.9, 1242000, "2020-04-21")
	insert_child(pg, "Update", "76989KJLVA2432", 0, 1, 183845, "2022-02-10")
	insert_child(pg, "Delete", "29189KLHVA1432", 0, 0, 365647, "2021-05-07")
	insert_child(pg, "Make", "09689KJHAA2431", 0, 0.3, 24, "2020-11-11")
	insert_child(pg, "Create", "09709KLKKH2432", 1, 0.3, 264851, "2021-02-21")
	insert_child(pg, "Group", "09209KJLKH2432", 1, 0.8, 537877, "2020-03-15")
	insert_child(pg, "Slide", "01909KJHYH1132", 0, 0.5, 9, "2018-03-02")
	insert_child(pg, "Drop", "09701KJHKH8750", 1, 0, 127255, "2018-01-01")
	insert_child(pg, "Beta", "09204QJHKN2432", 0, 0.6, 354, "2017-12-30")
	insert_child(pg, "Flag", "09709KXPIP2432", 1, 0, 1241000, "2021-04-21")
	insert_child(pg, "Upgrade", "75989ZJLVA2432", 0.8, 1, 183645, "2020-08-13")
	insert_child(pg, "Down", "28189KLHRA1432", 1, 0, 362647, "2020-06-17")
	insert_child(pg, "Note", "09689DJHAA2431", 0, 0.1, 29, "2021-09-11")
	insert_child(pg, "Click", "08189DJHAA2431", 1, 0.3, 209, "2020-07-04")
	insert_child(pg, "Drag", "08189DIHAA2981", 0, 0.7, 342628, "2022-05-04")

	pg.insert()


@whitelist_for_tests
def insert_translations():
	translation = [
		{
			"pagetype": "Translation",
			"language": "de",
			"source_text": "Other",
			"translated_text": "Sonstiges",
		},
		{
			"pagetype": "Translation",
			"language": "de",
			"source_text": "Genderqueer",
			"translated_text": "Nichtbinär",
		},
		{
			"pagetype": "Translation",
			"language": "de",
			"source_text": "Non-Conforming",
			"translated_text": "Nicht konform",
		},
		{
			"pagetype": "Translation",
			"language": "de",
			"source_text": "Prefer not to say",
			"translated_text": "Keine Angabe",
		},
	]

	for pg in translation:
		if not jingrow.db.exists("pg"):
			jingrow.get_pg(pg).insert()


@whitelist_for_tests
def create_blog_post():
	blog_category = jingrow.get_pg(
		{"name": "general", "pagetype": "Blog Category", "title": "general"}
	).insert(ignore_if_duplicate=True)

	blogger = jingrow.get_pg(
		{
			"name": "attachment blogger",
			"pagetype": "Blogger",
			"full_name": "attachment blogger",
			"short_name": "attachment blogger",
		}
	).insert(ignore_if_duplicate=True)

	return jingrow.get_pg(
		{
			"name": "test-blog-attachment-post",
			"pagetype": "Blog Post",
			"title": "test-blog-attachment-post",
			"blog_category": blog_category.name,
			"blogger": blogger.name,
			"content_type": "Rich Text",
		},
	).insert(ignore_if_duplicate=True)


@whitelist_for_tests
def create_test_user(username=None):
	name = username or UI_TEST_USER

	if jingrow.db.exists("User", name):
		return

	user = jingrow.new_pg("User")
	user.email = name
	user.first_name = "Jingrow"
	user.new_password = jingrow.local.conf.admin_password
	user.send_welcome_email = 0
	user.time_zone = "Asia/Kolkata"
	user.flags.ignore_password_policy = True
	user.insert(ignore_if_duplicate=True)

	user.reload()

	all_roles = set(jingrow.get_all("Role", pluck="name"))

	for role in all_roles - set(AUTOMATIC_ROLES):
		user.append("roles", {"role": role})

	user.save()


@whitelist_for_tests
def setup_tree_pagetype():
	jingrow.delete_pg_if_exists("PageType", "Custom Tree", force=True)

	jingrow.get_pg(
		{
			"pagetype": "PageType",
			"module": "Core",
			"custom": 1,
			"fields": [
				{"fieldname": "tree", "fieldtype": "Data", "label": "Tree"},
			],
			"permissions": [{"role": "System Manager", "read": 1}],
			"name": "Custom Tree",
			"is_tree": True,
			"naming_rule": "By fieldname",
			"autoname": "field:tree",
		}
	).insert()

	if not jingrow.db.exists("Custom Tree", "All Trees"):
		jingrow.get_pg({"pagetype": "Custom Tree", "tree": "All Trees"}).insert()


@whitelist_for_tests
def setup_image_pagetype():
	jingrow.delete_pg_if_exists("PageType", "Custom Image", force=True)

	jingrow.get_pg(
		{
			"pagetype": "PageType",
			"module": "Core",
			"custom": 1,
			"fields": [
				{"fieldname": "image", "fieldtype": "Attach Image", "label": "Image"},
			],
			"permissions": [{"role": "System Manager", "read": 1}],
			"name": "Custom Image",
			"image_field": "image",
		}
	).insert()


@whitelist_for_tests
def setup_inbox():
	jingrow.db.delete("User Email")

	user = jingrow.get_pg("User", jingrow.session.user)
	user.append("user_emails", {"email_account": "Email Linking"})
	user.save()


@whitelist_for_tests
def setup_default_view(view, force_reroute=None):
	jingrow.delete_pg_if_exists("Property Setter", "Event-main-default_view")
	jingrow.delete_pg_if_exists("Property Setter", "Event-main-force_re_route_to_default_view")

	jingrow.get_pg(
		{
			"is_system_generated": 0,
			"pagetype_or_field": "PageType",
			"pg_type": "Event",
			"property": "default_view",
			"property_type": "Select",
			"value": view,
			"pagetype": "Property Setter",
		}
	).insert()

	if force_reroute:
		jingrow.get_pg(
			{
				"is_system_generated": 0,
				"pagetype_or_field": "PageType",
				"pg_type": "Event",
				"property": "force_re_route_to_default_view",
				"property_type": "Check",
				"value": "1",
				"pagetype": "Property Setter",
			}
		).insert()


@whitelist_for_tests
def create_kanban():
	if not jingrow.db.exists("Custom Field", "Note-kanban"):
		jingrow.get_pg(
			{
				"is_system_generated": 0,
				"dt": "Note",
				"label": "Kanban",
				"fieldname": "kanban",
				"insert_after": "seen_by",
				"fieldtype": "Select",
				"options": "Open\nClosed",
				"pagetype": "Custom Field",
			}
		).insert()

	if not jingrow.db.exists("Kanban Board", "_Note _Kanban"):
		jingrow.get_pg(
			{
				"pagetype": "Kanban Board",
				"name": "_Note _Kanban",
				"kanban_board_name": "_Note _Kanban",
				"reference_pagetype": "Note",
				"field_name": "kanban",
				"private": 1,
				"show_labels": 0,
				"columns": [
					{
						"column_name": "Open",
						"status": "Active",
						"indicator": "Gray",
					},
					{
						"column_name": "Closed",
						"status": "Active",
						"indicator": "Gray",
					},
				],
			}
		).insert()


@whitelist_for_tests
def create_todo(description):
	return jingrow.get_pg({"pagetype": "ToDo", "description": description}).insert()


@whitelist_for_tests
def create_todo_with_attachment_limit(description):
	from jingrow.custom.pagetype.property_setter.property_setter import make_property_setter

	make_property_setter("ToDo", None, "max_attachments", 12, "int", for_pagetype=True)

	return jingrow.get_pg({"pagetype": "ToDo", "description": description}).insert()


@whitelist_for_tests
def create_admin_kanban():
	if not jingrow.db.exists("Kanban Board", "Admin Kanban"):
		jingrow.get_pg(
			{
				"pagetype": "Kanban Board",
				"name": "Admin Kanban",
				"owner": "Administrator",
				"kanban_board_name": "Admin Kanban",
				"reference_pagetype": "ToDo",
				"field_name": "status",
				"private": 0,
				"show_labels": 0,
				"columns": [
					{
						"column_name": "Open",
						"status": "Active",
						"indicator": "Gray",
					},
					{
						"column_name": "Closed",
						"status": "Active",
						"indicator": "Gray",
					},
				],
			}
		).insert()


@whitelist_for_tests
def add_remove_role(action, user, role):
	user_pg = jingrow.get_pg("User", user)
	if action == "remove":
		user_pg.remove_roles(role)
	else:
		user_pg.add_roles(role)


@whitelist_for_tests
def publish_realtime(
	event=None,
	message=None,
	room=None,
	user=None,
	pagetype=None,
	pagename=None,
	task_id=None,
):
	jingrow.publish_realtime(
		event=event,
		message=message,
		room=room,
		user=user,
		pagetype=pagetype,
		pagename=pagename,
		task_id=task_id,
	)


@whitelist_for_tests
def publish_progress(duration=3, title=None, pagetype=None, pagename=None):
	# This should consider session user and only show it to current user.
	jingrow.enqueue(slow_task, duration=duration, title=title, pagetype=pagetype, pagename=pagename)


def slow_task(duration, title, pagetype, pagename):
	import time

	steps = 10

	for i in range(steps + 1):
		jingrow.publish_progress(i * 10, title=title, pagetype=pagetype, pagename=pagename)
		time.sleep(int(duration) / steps)
