# (c) cavaliba.com - test / views / data related objects

from django.core.cache import cache as cache_django
from django.test import TestCase, override_settings
from django.urls import reverse

import app_home.cache as cache
from tests import helper


class TestViewsDataRelated(TestCase):
    def setUp(self):
        cache.clear()
        cache_django.clear()

    def _setup_related_schemas(self):
        helper.add_schema("tschema_b", displayname="Schema B")
        helper.add_schema(
            "tschema_a",
            displayname="Schema A",
            field_definition={
                "ref_b": {
                    "dataformat": "schema",
                    "dataformat_ext": "tschema_b",
                }
            },
        )
        helper.add_instance("tschema_b", "inst_b1")
        helper.add_instance("tschema_b", "inst_b2")
        helper.add_instance("tschema_a", "inst_a1", fields={"ref_b": "inst_b1"})
        helper.add_instance("tschema_a", "inst_a2", fields={"ref_b": "inst_b1"})
        helper.add_instance("tschema_a", "inst_a3", fields={"ref_b": "inst_b2"})

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_detail_related_table_present(self):
        helper.add_admin_user(login="unittest")
        self._setup_related_schemas()

        from app_data.models import DataInstance

        b1 = DataInstance.objects.get(classname="tschema_b", keyname="inst_b1")

        response = self.client.get(
            reverse("app_data:instance_detail", kwargs={"id": b1.id}), follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "related-objects-2")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_detail_related_link_format(self):
        helper.add_admin_user(login="unittest")
        self._setup_related_schemas()

        from app_data.models import DataInstance

        b1 = DataInstance.objects.get(classname="tschema_b", keyname="inst_b1")

        response = self.client.get(
            reverse("app_data:instance_detail", kwargs={"id": b1.id}), follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "query=RELATED:tschema_b:inst_b1")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_list_related_filter(self):
        helper.add_admin_user(login="unittest")
        self._setup_related_schemas()

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "tschema_a"})
            + "?query=RELATED:tschema_b:inst_b1",
            follow=True,
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "inst_a1")
        self.assertContains(response, "inst_a2")
        self.assertNotContains(response, "inst_a3")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_list_related_filter_other_instance(self):
        helper.add_admin_user(login="unittest")
        self._setup_related_schemas()

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "tschema_a"})
            + "?query=RELATED:tschema_b:inst_b2",
            follow=True,
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "inst_a3")
        self.assertNotContains(response, "inst_a1")
        self.assertNotContains(response, "inst_a2")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_detail_related_link_format_ipam_ip(self):
        """ipam_ip's related-object links must use its own (hexip) keyname,
        same as any other schema - the RELATED: search side of this is
        special-cased in get_instance_ids_from_related(), not the link
        format itself."""
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            "tschema_ip",
            displayname="Schema IP",
            field_definition={"ip_address": {"dataformat": "ipv4", "displayname": "IP"}},
        )
        helper.add_instance("tschema_ip", "hostip1", fields={"ip_address": "10.50.50.50"})

        from app_data.data import Instance

        ipam = Instance.from_keyname(classname="ipam_ip", keyname="0a323232")
        self.assertIsNotNone(ipam)

        response = self.client.get(
            reverse("app_data:instance_detail", kwargs={"id": ipam.id}), follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "query=RELATED:ipam_ip:0a323232")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_list_related_filter_ipam_ip(self):
        """Clicking that link (RELATED:ipam_ip:<hexip>) must actually find the
        referencing instance - it's matched on ipv4-format EAV value (the IP,
        i.e. ipam_ip's displayname), not on ipam_ip's own opaque keyname."""
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            "tschema_ip",
            displayname="Schema IP",
            field_definition={"ip_address": {"dataformat": "ipv4", "displayname": "IP"}},
        )
        helper.add_instance("tschema_ip", "hostip1", fields={"ip_address": "10.50.50.50"})

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "tschema_ip"})
            + "?query=RELATED:ipam_ip:0a323232",
            follow=True,
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "hostip1")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_instance_list_related_filter_ipam_ip_unknown_keyname(self):
        """An unresolvable hexip keyname must fail closed (no results, no
        crash) rather than falling through to the generic schema:ipam_ip
        match (which would also find nothing, but for the wrong reason)."""
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            "tschema_ip",
            displayname="Schema IP",
            field_definition={"ip_address": {"dataformat": "ipv4", "displayname": "IP"}},
        )
        helper.add_instance("tschema_ip", "hostip1", fields={"ip_address": "10.50.50.50"})

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "tschema_ip"})
            + "?query=RELATED:ipam_ip:ffffffff",
            follow=True,
        )
        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "hostip1")
