# (c) cavaliba.com - tests / api / search

import json

from django.test import TestCase
from django.urls import reverse

import app_home.cache as cache
from tests import helper

ST_SCHEMA = "st_test"


class APISearchAuthTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_schema(classname=ST_SCHEMA)
        helper.add_instance(classname=ST_SCHEMA, keyname="obj-mkeyname")

    def test_api_search_no_auth(self):
        response = self.client.get(reverse("api:api_search"), {"query": "mkeyname"})
        self.assertEqual(response.status_code, 401)

    def test_api_search_no_permission(self):
        header = helper.add_apikey(keyname="noperm", acl="")
        response = self.client.get(reverse("api:api_search"), {"query": "mkeyname"}, headers=header)
        self.assertEqual(response.status_code, 401)


class APISearchResponseTest(TestCase):
    def setUp(self):
        cache.clear()
        self.header = helper.add_apikey_admin()
        helper.add_schema(classname=ST_SCHEMA)
        helper.add_instance(
            classname=ST_SCHEMA, keyname="obj-mkeyname", fields={"displayname": "Instance KN"}
        )

    def test_api_search_keyname_match(self):
        response = self.client.get(
            reverse("api:api_search"), {"query": "mkeyname"}, headers=self.header
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        keynames = {r["keyname"]: r["match"] for r in data["results"]}
        self.assertEqual(keynames.get("obj-mkeyname"), "keyname")

    def test_api_search_no_match(self):
        response = self.client.get(
            reverse("api:api_search"), {"query": "nosuchterm"}, headers=self.header
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(data["results"], [])

    def test_api_search_missing_query_param(self):
        response = self.client.get(reverse("api:api_search"), headers=self.header)
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(data["results"], [])

    def test_api_search_too_short_returns_400(self):
        response = self.client.get(reverse("api:api_search"), {"query": "ab"}, headers=self.header)
        self.assertEqual(response.status_code, 400)
        data = json.loads(response.content)
        self.assertIn("error", data)

    def test_api_search_dangerous_chars_returns_400(self):
        response = self.client.get(
            reverse("api:api_search"), {"query": "<script>alert(1)</script>"}, headers=self.header
        )
        self.assertEqual(response.status_code, 400)

    def test_api_search_schema_prefix_scopes_results(self):
        helper.add_schema(classname="st_other")
        helper.add_instance(classname="st_other", keyname="other-mkeyname")
        response = self.client.get(
            reverse("api:api_search"), {"query": f"{ST_SCHEMA}:mkeyname"}, headers=self.header
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        classnames = {r["classname"] for r in data["results"]}
        self.assertEqual(classnames, {ST_SCHEMA})


class APISearchPermissionFilterTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_instance(
            classname="site", keyname="site-mkeyname", fields={"displayname": "Site KN"}
        )

    def test_api_search_filters_unreadable_instances(self):
        header = helper.add_apikey(keyname="siteless", acl="p_data_access")
        response = self.client.get(reverse("api:api_search"), {"query": "mkeyname"}, headers=header)
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(data["results"], [])

    def test_api_search_shows_readable_instances(self):
        header = helper.add_apikey(keyname="sitereader", acl="p_data_access\np_data_site_read")
        response = self.client.get(reverse("api:api_search"), {"query": "mkeyname"}, headers=header)
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        keynames = {r["keyname"] for r in data["results"]}
        self.assertIn("site-mkeyname", keynames)
