import random
import string

import jingrow
from jingrow.core.pagetype.pagetype.test_pagetype import new_pagetype
from jingrow.database import savepoint
from jingrow.desk.form import linked_with
from jingrow.tests.utils import JingrowTestCase


class TestLinkedWith(JingrowTestCase):
	def setUp(self):
		parent_pagetype = new_pagetype("Parent PageType")
		parent_pagetype.is_submittable = 1
		parent_pagetype.insert()

		child_pagetype1 = new_pagetype(
			"Child PageType1",
			fields=[
				{
					"label": "Parent PageType",
					"fieldname": "parent_pagetype",
					"fieldtype": "Link",
					"options": "Parent PageType",
				},
				{
					"label": "Reference field",
					"fieldname": "reference_name",
					"fieldtype": "Dynamic Link",
					"options": "reference_pagetype",
				},
				{
					"label": "Reference Pagetype",
					"fieldname": "reference_pagetype",
					"fieldtype": "Link",
					"options": "PageType",
				},
			],
			unique=0,
		)
		child_pagetype1.is_submittable = 1
		child_pagetype1.insert()

		child_pagetype2 = new_pagetype(
			"Child PageType2",
			fields=[
				{
					"label": "Parent PageType",
					"fieldname": "parent_pagetype",
					"fieldtype": "Link",
					"options": "Parent PageType",
				},
				{
					"label": "Child PageType1",
					"fieldname": "child_pagetype1",
					"fieldtype": "Link",
					"options": "Child PageType1",
				},
			],
			unique=0,
		)
		child_pagetype2.is_submittable = 1
		child_pagetype2.insert()

	def tearDown(self):
		for pagetype in ["Parent PageType", "Child PageType1", "Child PageType2"]:
			jingrow.delete_pg("PageType", pagetype)
			jingrow.db.commit()

	def test_get_pagetype_references_by_link_field(self):
		references = linked_with.get_references_across_pagetypes_by_link_field(to_pagetypes=["Parent PageType"])
		self.assertEqual(len(references["Parent PageType"]), 3)
		self.assertIn(
			{"pagetype": "Child PageType1", "fieldname": "parent_pagetype"}, references["Parent PageType"]
		)
		self.assertIn(
			{"pagetype": "Child PageType2", "fieldname": "parent_pagetype"}, references["Parent PageType"]
		)

		references = linked_with.get_references_across_pagetypes_by_link_field(to_pagetypes=["Child PageType1"])
		self.assertEqual(len(references["Child PageType1"]), 2)
		self.assertIn(
			{"pagetype": "Child PageType2", "fieldname": "child_pagetype1"}, references["Child PageType1"]
		)

		references = linked_with.get_references_across_pagetypes_by_link_field(
			to_pagetypes=["Child PageType1", "Parent PageType"], limit_link_pagetypes=["Child PageType1"]
		)
		self.assertEqual(len(references["Child PageType1"]), 1)
		self.assertEqual(len(references["Parent PageType"]), 1)
		self.assertIn(
			{"pagetype": "Child PageType1", "fieldname": "parent_pagetype"}, references["Parent PageType"]
		)

	def test_get_pagetype_references_by_dlink_field(self):
		references = linked_with.get_references_across_pagetypes_by_dynamic_link_field(
			to_pagetypes=["Parent PageType"],
			limit_link_pagetypes=["Parent PageType", "Child PageType1", "Child PageType2"],
		)
		self.assertFalse(references)

		parent_record = jingrow.get_pg({"pagetype": "Parent PageType"}).insert()

		child_record = jingrow.get_pg(
			{
				"pagetype": "Child PageType1",
				"reference_pagetype": "Parent PageType",
				"reference_name": parent_record.name,
			}
		).insert()

		references = linked_with.get_references_across_pagetypes_by_dynamic_link_field(
			to_pagetypes=["Parent PageType"],
			limit_link_pagetypes=["Parent PageType", "Child PageType1", "Child PageType2"],
		)

		self.assertEqual(len(references["Parent PageType"]), 1)
		self.assertEqual(references["Parent PageType"][0]["pagetype"], "Child PageType1")
		self.assertEqual(references["Parent PageType"][0]["pagetype_fieldname"], "reference_pagetype")

		child_record.delete()
		parent_record.delete()

	def test_get_submitted_linked_pgs(self):
		parent_record = jingrow.get_pg({"pagetype": "Parent PageType"}).insert()

		child_record = jingrow.get_pg(
			{
				"pagetype": "Child PageType1",
				"reference_pagetype": "Parent PageType",
				"reference_name": parent_record.name,
				"pagestatus": 1,
			}
		).insert()

		linked_pgs = linked_with.get_submitted_linked_pgs(parent_record.pagetype, parent_record.name)["pgs"]
		self.assertIn(child_record.name, linked_pgs[0]["name"])
		child_record.cancel()
		child_record.delete()
		parent_record.delete()

	def test_check_delete_integrity(self):
		"""Don't allow deleting cancelled document if amendment exists"""
		pg = jingrow.get_pg({"pagetype": "Parent PageType"}).insert()
		pg.submit()
		pg.cancel()

		amendment = jingrow.copy_pg(pg)
		amendment.amended_from = pg.name
		amendment.pagestatus = 0
		amendment.insert()
		amendment.submit()

		self.assertRaises(jingrow.LinkExistsError, pg.delete)

	def test_reserved_keywords(self):
		dt_name = "Test " + "".join(random.sample(string.ascii_lowercase, 10))
		new_pagetype(
			dt_name,
			fields=[
				{
					"fieldname": "from",
					"fieldtype": "Link",
					"options": "PageType",
				},
				{
					"fieldname": "order",
					"fieldtype": "Dynamic Link",
					"options": "from",
				},
			],
			is_submittable=True,
		).insert()

		linked_pg = jingrow.new_pg(dt_name).insert().submit()

		second_pg = (
			jingrow.new_pg(dt_name, **{"from": linked_pg.pagetype, "order": linked_pg.name})
			.insert()
			.submit()
		)

		with savepoint(jingrow.LinkExistsError):
			linked_pg.cancel() and self.fail("Cancellation shouldn't have worked")

		second_pg.cancel()
		linked_pg.reload().cancel()
