"""
Reads Windows Firewall rules from the system registry and filters them by port.

This module looks inside the Windows Registry to find firewall rules created by
the operating system or group policies. Each rule is parsed into a structured
format (`FirewallRule`) so it's easier for the rest of the agent to work with.

The main job here is to answer questions like “Which firewall rules apply to
port 445?” or “Show me all rules that mention these ports.” To do that, the code
loads raw rule strings from known registry paths, breaks them into key/value
fields, normalizes them, and checks whether each rule applies to the port we're
interested in.

Everything returned is read-only — we never modify the firewall. This module is
simply a safe way for the agent to understand how Windows is configured and how
traffic to a given port might be allowed or blocked.
"""


import winreg
from typing import List, Dict
from .normalizer import FirewallRule, normalize_firewall_rule

FIREWALL_RULE_PATHS = [
    r"SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules",
    r"SOFTWARE\Policies\Microsoft\WindowsFirewall\FirewallRules",
]

def rule_matches_port(rule: FirewallRule, port: int) -> bool:
    # wildcard: rule applies to all ports
    if rule.local_ports == ["*"]:
        return True
    if not rule.local_ports:
        return False
    return port in rule.local_ports

def parse_raw_rule_string(raw: str) -> Dict[str, str]:
    parts = raw.split("|")
    result: Dict[str, str] = {}

    if parts:
        result["Version"] = parts[0]

    for part in parts[1:]:
        if "=" in part:
            key, value = part.split("=", 1)
            result[key] = value

    return result


def find_firewall_rules_by_port(port: int) -> List[FirewallRule]:
    matches: List[FirewallRule] = []

    for path in FIREWALL_RULE_PATHS:
        try:
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
        except FileNotFoundError:
            continue

        index = 0
        while True:
            try:
                value_name, value_data, value_type = winreg.EnumValue(key, index)
            except OSError:
                break  # no more values

            index += 1

            if value_type != winreg.REG_SZ:
                continue

            raw = parse_raw_rule_string(value_data)
            raw["ValueName"] = value_name
            raw["SourcePath"] = path

            # normalize into FirewallRule
            rule = normalize_firewall_rule(raw, raw["SourcePath"])

            # filter by port
            if rule_matches_port(rule, port):
                matches.append(rule)

    return matches


def find_firewall_rules_by_ports(ports: List[int]) -> Dict[int, List[FirewallRule]]:
    results: Dict[int, List[FirewallRule]] = {}
    for port in ports:
        results[port] = find_firewall_rules_by_port(port)
    return results


if __name__ == "__main__":
    rules = find_firewall_rules_by_port(445)
    for r in rules:
        print(r.to_json())
