# (c) cavaliba.com - tests / app_data.ipam.subnet_ip_list

from django.test import TestCase, override_settings

import app_home.cache as cache
from app_data.ipam import subnet_ip_list
from tests import helper


class IpamSubnetIpListTest(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_schema(
            classname="iplisttest",
            field_definition={"ip_address": {"dataformat": "ipv4", "displayname": "IP"}},
        )

    def test_lists_ips_within_subnet_ordered_by_keyname(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.20"})
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(
            [row["displayname"] for row in result["rows"]], ["203.0.113.10", "203.0.113.20"]
        )

    def test_excludes_ips_outside_subnet(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})
        helper.add_instance(classname="ipam_ip", fields={"displayname": "198.51.100.10"})

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(result["total"], 1)
        self.assertEqual(result["rows"][0]["displayname"], "203.0.113.10")

    def test_collected_flag(self):
        helper.add_instance(
            classname="ipam_ip", fields={"displayname": "203.0.113.10", "collected": True}
        )

        result = subnet_ip_list("203.0.113.0/24")

        self.assertTrue(result["rows"][0]["collected"])

    def test_description_populated_for_manually_curated_entry(self):
        helper.add_instance(
            classname="ipam_ip",
            fields={"displayname": "203.0.113.10", "description": "Gateway"},
        )

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(result["rows"][0]["description"], "Gateway")

    def test_description_defaults_to_empty_string(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(result["rows"][0]["description"], "")

    def test_referrers_populated_from_eav(self):
        helper.add_instance(
            classname="iplisttest", keyname="host01", fields={"ip_address": "203.0.113.10"}
        )

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(result["total"], 1)
        referrers = result["rows"][0]["referrers"]
        self.assertEqual(len(referrers), 1)
        self.assertEqual(referrers[0]["classname"], "iplisttest")
        self.assertEqual(referrers[0]["keyname"], "host01")

    def test_not_gated_on_subnet_size(self):
        # what used to refuse anything wider than a /22 outright now lists the IPs it
        # holds, however wide the prefix - the gate is the IP count
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})

        self.assertEqual(subnet_ip_list("203.0.113.0/24")["total"], 1)
        self.assertEqual(subnet_ip_list("203.0.0.0/8")["total"], 1)
        self.assertEqual(subnet_ip_list("0.0.0.0/0")["total"], 1)

    def test_truncated_to_limit_with_full_total(self):
        for last in (10, 20, 30):
            helper.add_instance(classname="ipam_ip", fields={"displayname": f"203.0.113.{last}"})

        result = subnet_ip_list("203.0.113.0/24", limit=2)

        self.assertEqual(result["total"], 3)
        self.assertTrue(result["truncated"])
        self.assertEqual(
            [row["displayname"] for row in result["rows"]], ["203.0.113.10", "203.0.113.20"]
        )

    def test_not_truncated_when_total_fits_the_limit(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})

        result = subnet_ip_list("203.0.113.0/24", limit=1)

        self.assertEqual(result["total"], 1)
        self.assertFalse(result["truncated"])
        self.assertEqual(len(result["rows"]), 1)

    @override_settings(CAVALIBA_IPAM_IP_LIST_MAX=2)
    def test_limit_defaults_to_setting(self):
        for last in (10, 20, 30):
            helper.add_instance(classname="ipam_ip", fields={"displayname": f"203.0.113.{last}"})

        result = subnet_ip_list("203.0.113.0/24")

        self.assertEqual(len(result["rows"]), 2)
        self.assertEqual(result["total"], 3)
        self.assertTrue(result["truncated"])

    def test_invalid_cidr_is_empty_not_an_error(self):
        self.assertEqual(subnet_ip_list("not-a-cidr"), {"rows": [], "total": 0, "truncated": False})

    def test_empty_subnet_returns_empty(self):
        self.assertEqual(
            subnet_ip_list("203.0.113.0/24"), {"rows": [], "total": 0, "truncated": False}
        )
