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

import json

import jingrow
from jingrow.core.pagetype.pagetype.pagetype import InvalidFieldNameError
from jingrow.core.pagetype.pagetype.test_pagetype import new_pagetype
from jingrow.test_runner import make_test_records_for_pagetype
from jingrow.tests.utils import JingrowTestCase

test_dependencies = ["Custom Field", "Property Setter"]


class TestCustomizeForm(JingrowTestCase):
	def insert_custom_field(self):
		jingrow.delete_pg_if_exists("Custom Field", "Event-custom_test_field")
		self.field = jingrow.get_pg(
			{
				"pagetype": "Custom Field",
				"fieldname": "custom_test_field",
				"dt": "Event",
				"label": "Test Custom Field",
				"description": "A Custom Field for Testing",
				"fieldtype": "Select",
				"in_list_view": 1,
				"options": "\nCustom 1\nCustom 2\nCustom 3",
				"default": "Custom 3",
				"insert_after": jingrow.get_meta("Event").fields[-1].fieldname,
			}
		).insert()

	def setUp(self):
		self.insert_custom_field()
		jingrow.db.delete("Property Setter", dict(pg_type="Event"))
		jingrow.db.commit()
		jingrow.clear_cache(pagetype="Event")

	def tearDown(self):
		jingrow.delete_pg("Custom Field", self.field.name)
		jingrow.db.commit()
		jingrow.clear_cache(pagetype="Event")

	def get_customize_form(self, pagetype=None):
		d = jingrow.get_pg("Customize Form")
		if pagetype:
			d.pg_type = pagetype
		d.run_method("fetch_to_customize")
		return d

	def test_fetch_to_customize(self):
		d = self.get_customize_form()
		self.assertEqual(d.pg_type, None)
		self.assertEqual(len(d.get("fields")), 0)

		d = self.get_customize_form("Event")
		self.assertEqual(d.pg_type, "Event")
		self.assertEqual(len(d.get("fields")), 38)

		d = self.get_customize_form("Event")
		self.assertEqual(d.pg_type, "Event")

		self.assertEqual(len(d.get("fields")), len(jingrow.get_pg("PageType", d.pg_type).fields) + 1)
		self.assertEqual(d.get("fields")[-1].fieldname, self.field.fieldname)
		self.assertEqual(d.get("fields", {"fieldname": "event_type"})[0].in_list_view, 1)

		return d

	def test_save_customization_property(self):
		d = self.get_customize_form("Event")
		self.assertEqual(
			jingrow.db.get_value("Property Setter", {"pg_type": "Event", "property": "allow_copy"}, "value"),
			None,
		)

		d.allow_copy = 1
		d.run_method("save_customization")
		self.assertEqual(
			jingrow.db.get_value("Property Setter", {"pg_type": "Event", "property": "allow_copy"}, "value"),
			"1",
		)

		d.allow_copy = 0
		d.run_method("save_customization")
		self.assertEqual(
			jingrow.db.get_value("Property Setter", {"pg_type": "Event", "property": "allow_copy"}, "value"),
			None,
		)

	def test_save_customization_field_property(self):
		d = self.get_customize_form("Event")
		self.assertEqual(
			jingrow.db.get_value(
				"Property Setter",
				{"pg_type": "Event", "property": "reqd", "field_name": "repeat_this_event"},
				"value",
			),
			None,
		)

		repeat_this_event_field = d.get("fields", {"fieldname": "repeat_this_event"})[0]
		repeat_this_event_field.reqd = 1
		d.run_method("save_customization")
		self.assertEqual(
			jingrow.db.get_value(
				"Property Setter",
				{"pg_type": "Event", "property": "reqd", "field_name": "repeat_this_event"},
				"value",
			),
			"1",
		)

		repeat_this_event_field = d.get("fields", {"fieldname": "repeat_this_event"})[0]
		repeat_this_event_field.reqd = 0
		d.run_method("save_customization")
		self.assertEqual(
			jingrow.db.get_value(
				"Property Setter",
				{"pg_type": "Event", "property": "reqd", "field_name": "repeat_this_event"},
				"value",
			),
			None,
		)

	def test_save_customization_custom_field_property(self):
		d = self.get_customize_form("Event")
		self.assertEqual(jingrow.db.get_value("Custom Field", self.field.name, "reqd"), 0)

		custom_field = d.get("fields", {"fieldname": self.field.fieldname})[0]
		custom_field.reqd = 1
		custom_field.no_copy = 1
		d.run_method("save_customization")
		self.assertEqual(jingrow.db.get_value("Custom Field", self.field.name, "reqd"), 1)
		self.assertEqual(jingrow.db.get_value("Custom Field", self.field.name, "no_copy"), 1)

		custom_field = d.get("fields", {"is_custom_field": True})[0]
		custom_field.reqd = 0
		custom_field.no_copy = 0
		d.run_method("save_customization")
		self.assertEqual(jingrow.db.get_value("Custom Field", self.field.name, "reqd"), 0)
		self.assertEqual(jingrow.db.get_value("Custom Field", self.field.name, "no_copy"), 0)

	def test_save_customization_new_field(self):
		d = self.get_customize_form("Event")
		last_fieldname = d.fields[-1].fieldname
		d.append(
			"fields",
			{
				"label": "Test Add Custom Field Via Customize Form",
				"fieldtype": "Data",
				"is_custom_field": 1,
			},
		)
		d.run_method("save_customization")

		custom_field_name = "Event-custom_test_add_custom_field_via_customize_form"
		self.assertEqual(
			jingrow.db.get_value("Custom Field", custom_field_name, "fieldtype"),
			"Data",
		)

		self.assertEqual(
			jingrow.db.get_value("Custom Field", custom_field_name, "insert_after"),
			last_fieldname,
		)

		jingrow.delete_pg("Custom Field", custom_field_name)
		self.assertEqual(jingrow.db.get_value("Custom Field", custom_field_name), None)

	def test_save_customization_remove_field(self):
		d = self.get_customize_form("Event")
		custom_field = d.get("fields", {"fieldname": self.field.fieldname})[0]
		d.get("fields").remove(custom_field)
		d.run_method("save_customization")

		self.assertEqual(jingrow.db.get_value("Custom Field", custom_field.name), None)

		jingrow.local.test_objects["Custom Field"] = []
		make_test_records_for_pagetype("Custom Field")

	def test_reset_to_defaults(self):
		d = jingrow.get_pg("Customize Form")
		d.pg_type = "Event"
		d.run_method("reset_to_defaults")

		self.assertEqual(d.get("fields", {"fieldname": "repeat_this_event"})[0].in_list_view, 0)

		jingrow.local.test_objects["Property Setter"] = []
		make_test_records_for_pagetype("Property Setter")

	def test_set_allow_on_submit(self):
		d = self.get_customize_form("Event")
		d.get("fields", {"fieldname": "subject"})[0].allow_on_submit = 1
		d.get("fields", {"fieldname": "custom_test_field"})[0].allow_on_submit = 1
		d.run_method("save_customization")

		d = self.get_customize_form("Event")

		# don't allow for standard fields
		self.assertEqual(d.get("fields", {"fieldname": "subject"})[0].allow_on_submit or 0, 0)

		# allow for custom field
		self.assertEqual(d.get("fields", {"fieldname": "custom_test_field"})[0].allow_on_submit, 1)

	def test_title_field_pattern(self):
		d = self.get_customize_form("Web Form")

		df = d.get("fields", {"fieldname": "title"})[0]

		# invalid fieldname
		df.default = """{pg_type} - {introduction_test}"""
		self.assertRaises(InvalidFieldNameError, d.run_method, "save_customization")

		# space in formatter
		df.default = """{pg_type} - {introduction text}"""
		self.assertRaises(InvalidFieldNameError, d.run_method, "save_customization")

		# valid fieldname
		df.default = """{pg_type} - {introduction_text}"""
		d.run_method("save_customization")

		# valid fieldname with escaped curlies
		df.default = """{{ {pg_type} }} - {introduction_text}"""
		d.run_method("save_customization")

		# undo
		df.default = None
		d.run_method("save_customization")

	def test_core_pagetype_customization(self):
		self.assertRaises(jingrow.ValidationError, self.get_customize_form, "User")

	def test_save_customization_length_field_property(self):
		# Using Notification Log pagetype as it doesn't have any other custom fields
		d = self.get_customize_form("Notification Log")

		new_document_length = 255
		document_name = d.get("fields", {"fieldname": "document_name"})[0]
		document_name.length = new_document_length
		d.run_method("save_customization")

		self.assertEqual(
			jingrow.db.get_value(
				"Property Setter",
				{"pg_type": "Notification Log", "property": "length", "field_name": "document_name"},
				"value",
			),
			str(new_document_length),
		)

		length = jingrow.db.sql(
			"""SELECT character_maximum_length
			FROM information_schema.columns
			WHERE table_name = 'tabNotification Log'
			AND column_name = 'document_name'"""
		)[0][0]

		self.assertEqual(length, new_document_length)

	def test_custom_link(self):
		try:
			# create a dummy pagetype linked to Event
			testdt_name = "Test Link for Event"
			testdt = new_pagetype(
				testdt_name, fields=[dict(fieldtype="Link", fieldname="event", options="Event")]
			).insert()

			testdt_name1 = "Test Link for Event 1"
			testdt1 = new_pagetype(
				testdt_name1, fields=[dict(fieldtype="Link", fieldname="event", options="Event")]
			).insert()

			# add a custom link
			d = self.get_customize_form("Event")

			d.append("links", dict(link_pagetype=testdt_name, link_fieldname="event", group="Tests"))
			d.append("links", dict(link_pagetype=testdt_name1, link_fieldname="event", group="Tests"))

			d.run_method("save_customization")

			jingrow.clear_cache()
			event = jingrow.get_meta("Event")

			# check links exist
			self.assertTrue([d.name for d in event.links if d.link_pagetype == testdt_name])
			self.assertTrue([d.name for d in event.links if d.link_pagetype == testdt_name1])

			# check order
			order = json.loads(event.links_order)
			self.assertListEqual(order, [d.name for d in event.links])

			# remove the link
			d = self.get_customize_form("Event")
			d.links = []
			d.run_method("save_customization")

			jingrow.clear_cache()
			event = jingrow.get_meta("Event")
			self.assertFalse([d.name for d in (event.links or []) if d.link_pagetype == testdt_name])
		finally:
			testdt.delete()
			testdt1.delete()

	def test_custom_internal_links(self):
		# add a custom internal link
		jingrow.clear_cache()
		d = self.get_customize_form("User Group")

		d.append(
			"links",
			dict(
				link_pagetype="User Group Member",
				parent_pagetype="User Group",
				link_fieldname="user",
				table_fieldname="user_group_members",
				group="Tests",
				custom=1,
			),
		)

		d.run_method("save_customization")

		jingrow.clear_cache()
		user_group = jingrow.get_meta("User Group")

		# check links exist
		self.assertTrue([d.name for d in user_group.links if d.link_pagetype == "User Group Member"])
		self.assertTrue([d.name for d in user_group.links if d.parent_pagetype == "User Group"])

		# remove the link
		d = self.get_customize_form("User Group")
		d.links = []
		d.run_method("save_customization")

		jingrow.clear_cache()
		user_group = jingrow.get_meta("Event")
		self.assertFalse([d.name for d in (user_group.links or []) if d.link_pagetype == "User Group Member"])

	def test_custom_action(self):
		test_route = "/app/List/PageType"

		# create a dummy action (route)
		d = self.get_customize_form("Event")
		d.append("actions", dict(label="Test Action", action_type="Route", action=test_route))
		d.run_method("save_customization")

		jingrow.clear_cache()
		event = jingrow.get_meta("Event")

		# check if added to meta
		action = [d for d in event.actions if d.label == "Test Action"]
		self.assertEqual(len(action), 1)
		self.assertEqual(action[0].action, test_route)

		# clear the action
		d = self.get_customize_form("Event")
		d.actions = []
		d.run_method("save_customization")

		jingrow.clear_cache()
		event = jingrow.get_meta("Event")

		action = [d for d in event.actions if d.label == "Test Action"]
		self.assertEqual(len(action), 0)

	def test_custom_label(self):
		d = self.get_customize_form("Event")

		# add label
		d.label = "Test Rename"
		d.run_method("save_customization")
		self.assertEqual(d.label, "Test Rename")

		# change label
		d.label = "Test Rename 2"
		d.run_method("save_customization")
		self.assertEqual(d.label, "Test Rename 2")

		# saving again to make sure existing label persists
		d.run_method("save_customization")
		self.assertEqual(d.label, "Test Rename 2")

		# clear label
		d.label = ""
		d.run_method("save_customization")
		self.assertEqual(d.label, "")

	def test_change_to_autoincrement_autoname(self):
		d = self.get_customize_form("Event")
		d.autoname = "autoincrement"

		with self.assertRaises(jingrow.ValidationError):
			d.run_method("save_customization")

	def test_system_generated_fields(self):
		pagetype = "Event"
		custom_field_name = "custom_test_field"

		custom_field = jingrow.get_pg("Custom Field", {"dt": pagetype, "fieldname": custom_field_name})
		custom_field.is_system_generated = 1
		custom_field.save()

		d = self.get_customize_form(pagetype)
		custom_field = d.getone("fields", {"fieldname": custom_field_name})
		custom_field.description = "Test Description"
		d.run_method("save_customization")

		property_setter_filters = {
			"pg_type": pagetype,
			"field_name": custom_field_name,
			"property": "description",
		}
		self.assertEqual(
			jingrow.db.get_value("Property Setter", property_setter_filters, "value"), "Test Description"
		)

	def test_custom_field_order(self):
		# shuffle fields
		customize_form = self.get_customize_form(pagetype="ToDo")
		customize_form.fields.insert(0, customize_form.fields.pop())
		customize_form.save_customization()

		field_order_property = json.loads(
			jingrow.db.get_value("Property Setter", {"pg_type": "ToDo", "property": "field_order"}, "value")
		)

		self.assertEqual(field_order_property, [df.fieldname for df in jingrow.get_meta("ToDo").fields])
