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

import base64

import requests

import jingrow
from jingrow.core.pagetype.user.user import generate_keys
from jingrow.jingrowclient import JingrowClient, JingrowException
from jingrow.model import default_fields
from jingrow.tests.utils import JingrowTestCase
from jingrow.utils.data import get_url


class TestJingrowClient(JingrowTestCase):
	PASSWORD = jingrow.conf.admin_password or "admin"

	def test_insert_many(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		server.insert_many(
			[
				{"pagetype": "Note", "title": "Sing"},
				{"pagetype": "Note", "title": "a"},
				{"pagetype": "Note", "title": "song"},
				{"pagetype": "Note", "title": "of"},
				{"pagetype": "Note", "title": "sixpence"},
			]
		)
		records = server.get_list("Note", fields=["title"])
		records = [r.get("title") for r in records]

		self.assertIn("Sing", records)
		self.assertIn("a", records)
		self.assertIn("song", records)
		self.assertIn("of", records)
		self.assertIn("sixpence", records)

	def test_create_pg(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		response = server.insert({"pagetype": "Note", "title": "test_create"})

		for field in default_fields:
			self.assertIn(field, response)

		self.assertEqual(response.get("pagetype"), "Note")
		self.assertEqual(response.get("title"), "test_create")

	def test_list_pgs(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		pg_list = server.get_list("Note")

		self.assertTrue(len(pg_list))

	def test_get_pg(self):
		USER = "Administrator"
		TITLE = "get_this"
		PAGETYPE = "Note"
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)

		NAME = server.insert({"pagetype": PAGETYPE, "title": TITLE}).get("name")
		pg = server.get_pg(PAGETYPE, NAME)

		for field in default_fields:
			self.assertIn(field, pg)

		self.assertEqual(pg.get("pagetype"), PAGETYPE)
		self.assertEqual(pg.get("name"), NAME)
		self.assertEqual(pg.get("title"), TITLE)
		self.assertEqual(pg.get("owner"), USER)

	def test_get_value_by_filters(self):
		CONTENT = "test get value"
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		server.insert({"pagetype": "Note", "title": "get_value", "content": CONTENT}).get("name")

		self.assertEqual(server.get_value("Note", "content", {"title": "get_value"}).get("content"), CONTENT)

	def test_get_value_by_name(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		CONTENT = "test get value"
		NAME = server.insert({"pagetype": "Note", "title": "get_value", "content": CONTENT}).get("name")

		self.assertEqual(server.get_value("Note", "content", NAME).get("content"), CONTENT)

	def test_get_value_with_malicious_query(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		server.insert({"pagetype": "Note", "title": "get_value"})

		self.assertRaises(
			JingrowException,
			server.get_value,
			"Note",
			"(select (password) from(__Auth) order by name desc limit 1)",
			{"title": "get_value"},
		)

	def test_get_single(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		server.set_value("Website Settings", "Website Settings", "title_prefix", "test-prefix")
		self.assertEqual(
			server.get_value("Website Settings", "title_prefix", "Website Settings").get("title_prefix"),
			"test-prefix",
		)
		self.assertEqual(
			server.get_value("Website Settings", "title_prefix").get("title_prefix"), "test-prefix"
		)
		jingrow.db.set_single_value("Website Settings", "title_prefix", "")

	def test_update_pg(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		resp = server.insert({"pagetype": "Note", "title": "Sing"})
		pg = server.get_pg("Note", resp.get("name"))

		CONTENT = "<h1>Hello, World!</h1>"
		pg["content"] = CONTENT
		pg = server.update(pg)
		self.assertTrue(pg["content"] == CONTENT)

	def test_update_child_pg(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		jingrow.db.delete("Contact", {"first_name": "George", "last_name": "Steevens"})
		jingrow.db.delete("Contact", {"first_name": "William", "last_name": "Shakespeare"})
		jingrow.db.delete("Communication", {"reference_pagetype": "Event"})
		jingrow.db.delete("Communication Link", {"link_pagetype": "Contact"})
		jingrow.db.delete("Event", {"subject": "Sing a song of sixpence"})
		jingrow.db.delete("Event Participants", {"reference_pagetype": "Contact"})
		jingrow.db.commit()

		# create multiple contacts
		server.insert_many(
			[
				{"pagetype": "Contact", "first_name": "George", "last_name": "Steevens"},
				{"pagetype": "Contact", "first_name": "William", "last_name": "Shakespeare"},
			]
		)

		# create an event with one of the created contacts
		event = server.insert(
			{
				"pagetype": "Event",
				"subject": "Sing a song of sixpence",
				"event_participants": [
					{"reference_pagetype": "Contact", "reference_pagename": "George Steevens"}
				],
			}
		)

		# update the event's contact to the second contact
		server.update(
			{
				"pagetype": "Event Participants",
				"name": event.get("event_participants")[0].get("name"),
				"reference_pagename": "William Shakespeare",
			}
		)

		# the change should run the parent document's validations and
		# create a Communication record with the new contact
		self.assertTrue(jingrow.db.exists("Communication Link", {"link_name": "William Shakespeare"}))

	def test_delete_pg(self):
		server = JingrowClient(get_url(), "Administrator", self.PASSWORD, verify=False)
		NAME_TO_DELETE = server.insert({"pagetype": "Note", "title": "Sing"}).get("name")
		server.delete("Note", NAME_TO_DELETE)
		self.assertFalse(jingrow.db.get_value("Note", NAME_TO_DELETE))

	def test_auth_via_api_key_secret(self):
		# generate API key and API secret for administrator
		keys = generate_keys("Administrator")
		jingrow.db.commit()
		generated_secret = jingrow.utils.password.get_decrypted_password(
			"User", "Administrator", fieldname="api_secret"
		)

		api_key = jingrow.db.get_value("User", "Administrator", "api_key")
		header = {"Authorization": f"token {api_key}:{generated_secret}"}
		res = requests.post(get_url() + "/api/action/jingrow.auth.get_logged_user", headers=header)

		self.assertEqual(res.status_code, 200)
		self.assertEqual("Administrator", res.json()["message"])
		self.assertEqual(keys["api_secret"], generated_secret)

		header = {
			"Authorization": "Basic {}".format(
				base64.b64encode(jingrow.safe_encode(f"{api_key}:{generated_secret}")).decode()
			)
		}
		res = requests.post(get_url() + "/api/action/jingrow.auth.get_logged_user", headers=header)
		self.assertEqual(res.status_code, 200)
		self.assertEqual("Administrator", res.json()["message"])

		# Valid api key, invalid api secret
		api_secret = "ksk&93nxoe3os"
		header = {"Authorization": f"token {api_key}:{api_secret}"}
		res = requests.post(get_url() + "/api/action/jingrow.auth.get_logged_user", headers=header)
		self.assertEqual(res.status_code, 401)

		# random api key and api secret
		api_key = "@3djdk3kld"
		api_secret = "ksk&93nxoe3os"
		header = {"Authorization": f"token {api_key}:{api_secret}"}
		res = requests.post(get_url() + "/api/action/jingrow.auth.get_logged_user", headers=header)
		self.assertEqual(res.status_code, 401)
