"""Vulnerability mixins for IPv6-related issues.

Includes checks such as predictable addressing and other IPv6 findings.
"""
from __future__ import annotations

import csv
from collections import defaultdict

from ptnetinspector.utils.ip_utils import (
    has_additional_data,
    is_global_unicast_ipv6,
    is_ipv6_predictable,
    is_link_local_ipv6,
)
from ptnetinspector.utils.path import get_csv_path


class IPv6PredictableMixin:
    def store_ipv6_vulnerability(self) -> None:
        role_dict = self.read_role_dict(self.role_file)
        if not role_dict:
            return

        addresses_file = get_csv_path("addresses.csv")
        if not addresses_file or not has_additional_data(addresses_file):
            return

        mode = self._filter_modes("p,a,a+")
        if not mode:
            return

        mac_ips = defaultdict(list)
        try:
            with open(addresses_file, newline="") as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    mac_ips[row["MAC"].strip()].append(row["IP"].strip())
        except (FileNotFoundError, KeyError):
            return

        existing_rows = self._load_existing_rows()
        new_rows = []

        for device_id, mac in role_dict.items():
            has_ipv6 = mac in mac_ips and any(is_global_unicast_ipv6(ip) or is_link_local_ipv6(ip) for ip in mac_ips[mac])

            # Check for global unicast predictability
            has_global_unicast = mac in mac_ips and any(is_global_unicast_ipv6(ip) for ip in mac_ips[mac])
            label_global = "2" if not has_global_unicast else "0"
            if has_global_unicast:
                for ip in mac_ips[mac]:
                    if is_global_unicast_ipv6(ip) and is_ipv6_predictable(ip, mac):
                        label_global = "1"
                        break

            row = (
                str(device_id),
                mac,
                mode,
                "6",
                "PTV-NET-IDENT-6-PREDICT-GLOBIP",
                "Device uses predictable IPv6 global address",
                label_global,
            )
            self._add_vuln_if_new(row, existing_rows, new_rows)

            # Check for link-local predictability
            has_link_local = mac in mac_ips and any(is_link_local_ipv6(ip) for ip in mac_ips[mac])
            label_linklocal = "2" if not has_link_local else "0"
            if has_link_local:
                for ip in mac_ips[mac]:
                    if is_link_local_ipv6(ip) and is_ipv6_predictable(ip, mac):
                        label_linklocal = "1"
                        break

            row = (
                str(device_id),
                mac,
                mode,
                "6",
                "PTV-NET-IDENT-6-PREDICT-LINKLOCALIP",
                "Device uses predictable IPv6 link-local address",
                label_linklocal,
            )
            self._add_vuln_if_new(row, existing_rows, new_rows)

        self._write_vulnerabilities(new_rows)
