"""Structured change parser for RouterOS unified diffs.

Extracts component names and human-readable summaries from unified diffs
of RouterOS configurations. Each distinct RouterOS section in the diff
produces one change entry with component path, summary, and raw diff lines.
"""

from __future__ import annotations

import re
from collections import defaultdict


def _path_to_component(path: str) -> str:
    """Convert RouterOS path to component format.

    '/ip firewall filter' -> 'ip/firewall/filter'
    """
    return path.strip().lstrip("/").replace(" ", "/")


def _component_label(component: str) -> str:
    """Extract human-readable label from component path.

    'ip/firewall/filter' -> 'firewall filter'
    Last two segments joined with space, or last segment if only one.
    """
    parts = component.split("/")
    if len(parts) >= 2:
        return " ".join(parts[-2:])
    return parts[-1]


def _make_summary(adds: int, removes: int, component: str) -> str:
    """Generate human-readable summary for a component's changes."""
    label = _component_label(component)
    if adds > 0 and removes > 0:
        n = max(adds, removes)
        noun = "rule" if n == 1 else "rules"
        return f"Modified {n} {label} {noun}"
    elif adds > 0:
        noun = "rule" if adds == 1 else "rules"
        return f"Added {adds} {label} {noun}"
    else:
        noun = "rule" if removes == 1 else "rules"
        return f"Removed {removes} {label} {noun}"


_ROUTEROS_PATH_RE = re.compile(r"^(/[a-z][a-z0-9 /\-]*)", re.IGNORECASE)

FALLBACK_COMPONENT = "system/general"


def parse_diff_changes(diff_text: str) -> list[dict]:
    """Parse a unified diff of RouterOS config into structured changes.

    Returns list of dicts sorted by component, one per distinct component:
        {"component": "ip/firewall/filter",
         "summary": "Added 2 firewall filter rules",
         "raw_line": "+add chain=..."}
    """
    lines = diff_text.splitlines()

    current_section: str | None = None

    # Track per-component: adds, removes, raw_lines
    components: dict[str, dict] = defaultdict(lambda: {"adds": 0, "removes": 0, "raw_lines": []})

    for line in lines:
        # Skip unified diff headers
        if line.startswith("---") or line.startswith("+++") or line.startswith("@@"):
            continue

        # Determine the raw content (strip the diff prefix for path detection)
        if line.startswith("+") or line.startswith("-"):
            content = line[1:]
            is_change = True
            is_add = line.startswith("+")
        elif line.startswith(" "):
            content = line[1:]
            is_change = False
            is_add = False
        else:
            content = line
            is_change = False
            is_add = False

        # Check if content contains a RouterOS path header
        path_match = _ROUTEROS_PATH_RE.match(content.strip())
        if path_match:
            candidate = path_match.group(1).strip()
            # Must have at least 2 chars after / to be a real path
            if len(candidate) > 1:
                current_section = _path_to_component(candidate)

        # Record changed lines
        if is_change:
            section = current_section or FALLBACK_COMPONENT
            components[section]["raw_lines"].append(line)
            if is_add:
                components[section]["adds"] += 1
            else:
                components[section]["removes"] += 1

    # Build result list
    result = []
    for component in sorted(components.keys()):
        data = components[component]
        if data["adds"] == 0 and data["removes"] == 0:
            continue
        result.append(
            {
                "component": component,
                "summary": _make_summary(data["adds"], data["removes"], component),
                "raw_line": "\n".join(data["raw_lines"]),
            }
        )

    return result
