# Copyright (c) 2015, JINGROW and Contributors

from unittest.mock import patch

import jingrow
from jingrow.tests.utils import JingrowTestCase
from jingrow.utils import get_site_url


class TestClient(JingrowTestCase):
	def test_set_value(self):
		todo = jingrow.get_pg(dict(pagetype="ToDo", description="test")).insert()
		jingrow.set_value("ToDo", todo.name, "description", "test 1")
		self.assertEqual(jingrow.get_value("ToDo", todo.name, "description"), "test 1")

		jingrow.set_value("ToDo", todo.name, {"description": "test 2"})
		self.assertEqual(jingrow.get_value("ToDo", todo.name, "description"), "test 2")

	def test_delete(self):
		from jingrow.client import delete
		from jingrow.desk.pagetype.note.note import Note

		note = jingrow.get_pg(
			pagetype="Note",
			title=jingrow.generate_hash(length=8),
			content="test",
			seen_by=[{"user": "Administrator"}],
		).insert()

		child_row_name = note.seen_by[0].name

		with patch.object(Note, "save") as save:
			delete("Note Seen By", child_row_name)
			save.assert_called()

		delete("Note", note.name)

		self.assertFalse(jingrow.db.exists("Note", note.name))
		self.assertRaises(jingrow.DoesNotExistError, delete, "Note", note.name)
		self.assertRaises(jingrow.DoesNotExistError, delete, "Note Seen By", child_row_name)

	def test_http_valid_method_access(self):
		from jingrow.client import delete
		from jingrow.handler import execute_cmd

		jingrow.set_user("Administrator")

		jingrow.local.request = jingrow._dict()
		jingrow.local.request.method = "POST"

		jingrow.local.form_dict = jingrow._dict(
			{"pg": dict(pagetype="ToDo", description="Valid http method"), "cmd": "jingrow.client.save"}
		)
		todo = execute_cmd("jingrow.client.save")

		self.assertEqual(todo.get("description"), "Valid http method")

		delete("ToDo", todo.name)

	def test_http_invalid_method_access(self):
		from jingrow.handler import execute_cmd

		jingrow.set_user("Administrator")

		jingrow.local.request = jingrow._dict()
		jingrow.local.request.method = "GET"

		jingrow.local.form_dict = jingrow._dict(
			{"pg": dict(pagetype="ToDo", description="Invalid http method"), "cmd": "jingrow.client.save"}
		)

		self.assertRaises(jingrow.PermissionError, execute_cmd, "jingrow.client.save")

	def test_run_pg_method(self):
		from jingrow.handler import execute_cmd

		if not jingrow.db.exists("Report", "Test Run Pg Method"):
			report = jingrow.get_pg(
				{
					"pagetype": "Report",
					"ref_pagetype": "User",
					"report_name": "Test Run Pg Method",
					"report_type": "Query Report",
					"is_standard": "No",
					"roles": [{"role": "System Manager"}],
				}
			).insert()
		else:
			report = jingrow.get_pg("Report", "Test Run Pg Method")

		jingrow.local.request = jingrow._dict()
		jingrow.local.request.method = "GET"

		# Whitelisted, works as expected
		jingrow.local.form_dict = jingrow._dict(
			{
				"dt": report.pagetype,
				"dn": report.name,
				"method": "toggle_disable",
				"cmd": "run_pg_method",
				"args": 0,
			}
		)

		execute_cmd(jingrow.local.form_dict.cmd)

		# Not whitelisted, throws permission error
		jingrow.local.form_dict = jingrow._dict(
			{
				"dt": report.pagetype,
				"dn": report.name,
				"method": "create_report_py",
				"cmd": "run_pg_method",
				"args": 0,
			}
		)

		self.assertRaises(jingrow.PermissionError, execute_cmd, jingrow.local.form_dict.cmd)

	def test_array_values_in_request_args(self):
		import requests

		from jingrow.auth import CookieManager, LoginManager

		jingrow.utils.set_request(path="/")
		jingrow.local.cookie_manager = CookieManager()
		jingrow.local.login_manager = LoginManager()
		jingrow.local.login_manager.login_as("Administrator")
		params = {
			"pagetype": "PageType",
			"fields": ["name", "modified"],
			"sid": jingrow.session.sid,
		}
		headers = {
			"accept": "application/json",
			"content-type": "application/json",
		}
		url = get_site_url(jingrow.local.site)
		url += "/api/action/jingrow.client.get_list"

		res = requests.post(url, json=params, headers=headers)
		self.assertEqual(res.status_code, 200)
		data = res.json()
		first_item = data["message"][0]
		self.assertTrue("name" in first_item)
		self.assertTrue("modified" in first_item)

	def test_client_get(self):
		from jingrow.client import get

		todo = jingrow.get_pg(pagetype="ToDo", description="test").insert()
		filters = {"name": todo.name}
		filters_json = jingrow.as_json(filters)

		self.assertEqual(get("ToDo", filters=filters).description, "test")
		self.assertEqual(get("ToDo", filters=filters_json).description, "test")
		self.assertEqual(get("System Settings", "", "").pagetype, "System Settings")
		self.assertEqual(get("ToDo", filters={}), get("ToDo", filters="{}"))
		todo.delete()

	def test_client_validatate_link(self):
		from jingrow.client import validate_link

		# Basic test
		self.assertTrue(validate_link("User", "Guest"))

		# fixes capitalization
		if jingrow.db.db_type == "mariadb":
			self.assertEqual(validate_link("User", "GueSt"), {"name": "Guest"})

		# Fetch
		self.assertEqual(validate_link("User", "Guest", fields=["enabled"]), {"name": "Guest", "enabled": 1})

		# Permissions
		with self.set_user("Guest"), self.assertRaises(jingrow.PermissionError):
			self.assertEqual(
				validate_link("User", "Guest", fields=["enabled"]), {"name": "Guest", "enabled": 1}
			)

	def test_client_insert(self):
		from jingrow.client import insert

		def get_random_title():
			return f"test-{jingrow.generate_hash()}"

		# test insert dict
		pg = {"pagetype": "Note", "title": get_random_title(), "content": "test"}
		note1 = insert(pg)
		self.assertTrue(note1)

		# test insert json
		pg["title"] = get_random_title()
		json_pg = jingrow.as_json(pg)
		note2 = insert(json_pg)
		self.assertTrue(note2)

		# test insert child pg without parent fields
		child_pg = {"pagetype": "Note Seen By", "user": "Administrator"}
		with self.assertRaises(jingrow.ValidationError):
			insert(child_pg)

		# test insert child pg with parent fields
		child_pg = {
			"pagetype": "Note Seen By",
			"user": "Administrator",
			"parenttype": "Note",
			"parent": note1.name,
			"parentfield": "seen_by",
		}
		note3 = insert(child_pg)
		self.assertTrue(note3)

		# cleanup
		jingrow.delete_pg("Note", note1.name)
		jingrow.delete_pg("Note", note2.name)

	def test_client_insert_many(self):
		from jingrow.client import insert, insert_many

		def get_random_title():
			return f"test-{jingrow.generate_hash(length=5)}"

		# insert a (parent) pg
		note1 = {"pagetype": "Note", "title": get_random_title(), "content": "test"}
		note1 = insert(note1)

		pg_list = [
			{
				"pagetype": "Note Seen By",
				"user": "Administrator",
				"parenttype": "Note",
				"parent": note1.name,
				"parentfield": "seen_by",
			},
			{
				"pagetype": "Note Seen By",
				"user": "Administrator",
				"parenttype": "Note",
				"parent": note1.name,
				"parentfield": "seen_by",
			},
			{
				"pagetype": "Note Seen By",
				"user": "Administrator",
				"parenttype": "Note",
				"parent": note1.name,
				"parentfield": "seen_by",
			},
			{"pagetype": "Note", "title": "not-a-random-title", "content": "test"},
			{"pagetype": "Note", "title": get_random_title(), "content": "test"},
			{"pagetype": "Note", "title": get_random_title(), "content": "test"},
			{"pagetype": "Note", "title": "another-note-title", "content": "test"},
		]

		# insert all pgs
		pgs = insert_many(pg_list)

		self.assertEqual(len(pgs), 7)
		self.assertEqual(jingrow.db.get_value("Note", pgs[3], "title"), "not-a-random-title")
		self.assertEqual(jingrow.db.get_value("Note", pgs[6], "title"), "another-note-title")
		self.assertIn(note1.name, pgs)

		# cleanup
		for pg in pgs:
			jingrow.delete_pg("Note", pg)
