from unittest.mock import MagicMock, patch

from discovery.nmap_scan import NetworkScanner


class TestValidateSubnet:
    def test_valid_cidr(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        assert scanner.validate_subnet("192.168.1.0/24") is True

    def test_valid_cidr_16(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        assert scanner.validate_subnet("10.0.0.0/16") is True

    def test_invalid_subnet(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        assert scanner.validate_subnet("not-a-subnet") is False

    def test_empty_string(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        assert scanner.validate_subnet("") is False


class TestGetNetworkInfo:
    def test_basic_info(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        info = scanner.get_network_info("192.168.1.0/24")

        assert info['network_address'] == "192.168.1.0"
        assert info['broadcast_address'] == "192.168.1.255"
        assert info['netmask'] == "255.255.255.0"
        assert info['total_addresses'] == 256
        assert info['usable_addresses'] == 254
        assert info['prefix_length'] == 24

    def test_slash_30(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        info = scanner.get_network_info("10.0.0.0/30")

        assert info['total_addresses'] == 4
        assert info['usable_addresses'] == 2

    def test_slash_32(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        info = scanner.get_network_info("10.0.0.1/32")

        assert info['total_addresses'] == 1
        assert info['usable_addresses'] == 0


class TestScanSubnet:
    @patch("discovery.nmap_scan.nmap.PortScanner")
    def test_scan_returns_hosts(self, mock_scanner_cls):
        mock_nm = MagicMock()
        mock_scanner_cls.return_value = mock_nm

        mock_nm.all_hosts.return_value = ["192.168.1.1", "192.168.1.10"]
        mock_nm.__getitem__ = MagicMock()

        host_mock = MagicMock()
        host_mock.state.return_value = "up"
        host_mock.__getitem__ = MagicMock(return_value={})
        host_mock.__contains__ = MagicMock(return_value=False)
        host_mock.all_protocols.return_value = []
        mock_nm.__getitem__.return_value = host_mock

        scanner = NetworkScanner()
        results = scanner.scan_subnet("192.168.1.0/24", "ping")

        assert results['total_hosts'] == 2
        assert results['subnet'] == "192.168.1.0/24"
        assert len(results['hosts']) == 2

    def test_scan_invalid_subnet_raises(self):
        scanner = NetworkScanner.__new__(NetworkScanner)
        scanner.nm = MagicMock()
        scanner.logger = MagicMock()

        try:
            scanner.scan_subnet("invalid", "ping")
            assert False, "Should have raised ValueError"
        except ValueError:
            pass
