# (c) cavaliba.com - tests / app_data.ipam.build_vlan_rows + ipam_vlan instance_list hook

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

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


class IpamVlanListOccupancyTest(TestCase):
    def setUp(self):
        cache.clear()
        # TEST-NET-3 (RFC 5737) - guaranteed not to overlap the builtin
        # 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12 seeds (220-ipam.yml)
        helper.add_instance(
            classname="ipam_subnet",
            keyname="203.0.113.0/28",
            fields={"description": "first"},
        )
        helper.add_instance(
            classname="ipam_subnet",
            keyname="203.0.113.16/28",
            fields={"description": "second"},
        )

    def _vlan(self, keyname="vlan01"):
        helper.add_instance(classname="ipam_vlan", keyname=keyname)
        from app_data.data import Instance

        return Instance.from_keyname(classname="ipam_vlan", keyname=keyname)

    def test_one_subnet_reports_size_and_occupancy(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan01",
            fields={"displayname": "VLAN 01", "vlan_id": 10, "subnet": ["203.0.113.0/28"]},
        )

        rows = build_vlan_rows([{"id": 1, "keyname": "vlan01", "displayname": "VLAN 01"}])

        self.assertEqual(len(rows), 1)
        row = rows[0]
        self.assertEqual(row["vlan_id"], "10")
        self.assertEqual(len(row["subnets"]), 1)
        subnet = row["subnets"][0]
        self.assertEqual(subnet["keyname"], "203.0.113.0/28")
        self.assertEqual(subnet["size"], 16)
        self.assertEqual(subnet["occupancy"]["count"], 1)

    def test_zero_subnets_returns_empty_list(self):
        helper.add_instance(
            classname="ipam_vlan", keyname="vlan_empty", fields={"displayname": "Empty VLAN"}
        )

        rows = build_vlan_rows([{"id": 1, "keyname": "vlan_empty", "displayname": "Empty VLAN"}])

        self.assertEqual(rows[0]["subnets"], [])

    def test_two_subnets_have_independent_occupancy(self):
        # 203.0.113.0/28 covers .0-.15, 203.0.113.16/28 covers .16-.31
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.5"})
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.20"})
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_multi",
            fields={
                "displayname": "Multi VLAN",
                "subnet": ["203.0.113.0/28", "203.0.113.16/28"],
            },
        )

        rows = build_vlan_rows([{"id": 1, "keyname": "vlan_multi", "displayname": "Multi VLAN"}])

        by_keyname = {s["keyname"]: s for s in rows[0]["subnets"]}
        self.assertEqual(by_keyname["203.0.113.0/28"]["occupancy"]["count"], 2)
        self.assertEqual(by_keyname["203.0.113.16/28"]["occupancy"]["count"], 1)

    def test_unknown_subnet_keyname_skipped(self):
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_dangling",
            fields={"displayname": "Dangling VLAN", "subnet": ["203.0.113.0/28"]},
        )
        from app_data.models import DataInstance

        DataInstance.objects.filter(classname="ipam_subnet", keyname="203.0.113.0/28").delete()

        rows = build_vlan_rows(
            [{"id": 1, "keyname": "vlan_dangling", "displayname": "Dangling VLAN"}]
        )

        self.assertEqual(rows[0]["subnets"], [])

    def test_same_subnet_shared_by_two_vlans_computed_independently(self):
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_a",
            fields={"displayname": "VLAN A", "subnet": ["203.0.113.0/28"]},
        )
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_b",
            fields={"displayname": "VLAN B", "subnet": ["203.0.113.0/28"]},
        )

        rows = build_vlan_rows(
            [
                {"id": 1, "keyname": "vlan_a", "displayname": "VLAN A"},
                {"id": 2, "keyname": "vlan_b", "displayname": "VLAN B"},
            ]
        )

        self.assertEqual(rows[0]["subnets"][0]["occupancy"]["count"], 1)
        self.assertEqual(rows[1]["subnets"][0]["occupancy"]["count"], 1)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_list_view_renders_subnet_occupancy(self):
        helper.add_admin_user(login="unittest")
        helper.add_instance(classname="ipam_ip", fields={"displayname": "203.0.113.10"})
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan01",
            fields={"displayname": "VLAN 01", "vlan_id": 10, "subnet": ["203.0.113.0/28"]},
        )

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "ipam_vlan"})
        )

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "vlan01")
        self.assertContains(response, "203.0.113.0/28")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_list_view_multi_subnet_uses_one_row_per_subnet(self):
        helper.add_admin_user(login="unittest")
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_multi",
            fields={
                "displayname": "Multi VLAN",
                "subnet": ["203.0.113.0/28", "203.0.113.16/28"],
            },
        )

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "ipam_vlan"})
        )

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "203.0.113.0/28")
        self.assertContains(response, "203.0.113.16/28")
        # VLAN-level columns (keyname/name/description/VLAN ID) are
        # row-spanned once across both subnet rows, not repeated per row
        self.assertContains(response, 'rowspan="2"', count=4)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_list_view_falls_back_to_dataview_when_not_default(self):
        helper.add_admin_user(login="unittest")
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan01",
            fields={"displayname": "VLAN 01", "subnet": ["203.0.113.0/28"]},
        )
        helper.add_instance(
            classname="_dataview",
            keyname="ipam_vlan_alt",
            fields={
                "target_class": "ipam_vlan",
                "displayname": "Alt",
                "content": "columns:\n  - keyname\n",
            },
        )

        response = self.client.get(
            reverse("app_data:instance_list", kwargs={"classname": "ipam_vlan"}),
            {"dv": "ipam_vlan_alt"},
        )

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "vlan01")
        # the alt dataview only shows "keyname" - the hook's own computed
        # subnet detail column (and the CIDR it would render) is absent
        self.assertNotContains(response, "203.0.113.0/28")
