"""Tests for config change parser.

Tests the parse_diff_changes function that extracts structured RouterOS
component changes from unified diffs.
"""

from app.services.config_change_parser import parse_diff_changes


class TestParseDiffChanges:
    """Tests for parse_diff_changes()."""

    def test_firewall_filter_additions(self):
        """Test 1: Diff with additions under /ip firewall filter produces correct component and summary."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,3 +1,5 @@\n"
            " /ip firewall filter\n"
            " add chain=input action=accept\n"
            "+add chain=forward action=accept protocol=tcp dst-port=80\n"
            "+add chain=forward action=accept protocol=tcp dst-port=443\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 1
        assert changes[0]["component"] == "ip/firewall/filter"
        assert "Added" in changes[0]["summary"]
        assert "2" in changes[0]["summary"]
        assert changes[0]["raw_line"] is not None

    def test_multiple_sections(self):
        """Test 2: Diff with changes under multiple sections produces two change entries."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,4 +1,6 @@\n"
            " /ip address\n"
            "+add address=10.0.0.1/24 interface=ether1\n"
            " /ip dns\n"
            "+set servers=8.8.8.8,8.8.4.4\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 2
        components = [c["component"] for c in changes]
        assert "ip/address" in components
        assert "ip/dns" in components

    def test_removals_only(self):
        """Test 3: Diff with only removals produces summary like 'Removed 1 NAT rule'."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,3 +1,2 @@\n"
            " /ip firewall nat\n"
            " add chain=srcnat action=masquerade\n"
            "-add chain=dstnat action=dst-nat to-addresses=192.168.1.100\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 1
        assert changes[0]["component"] == "ip/firewall/nat"
        assert "Removed" in changes[0]["summary"]
        assert "1" in changes[0]["summary"]

    def test_modifications_both_add_and_remove(self):
        """Test 4: Diff with both + and - lines under same component produces 'Modified' summary."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,3 +1,3 @@\n"
            " /ip firewall filter\n"
            "-add chain=input action=accept protocol=tcp dst-port=22\n"
            "-add chain=input action=accept protocol=tcp dst-port=23\n"
            "+add chain=input action=accept protocol=tcp dst-port=22 comment=ssh\n"
            "+add chain=input action=accept protocol=tcp dst-port=443 comment=https\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 1
        assert "Modified" in changes[0]["summary"]
        assert "2" in changes[0]["summary"]

    def test_no_path_header_fallback(self):
        """Test 5: Diff with no RouterOS path headers uses system/general as fallback."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,3 +1,3 @@\n"
            " # RouterOS config\n"
            "-# version 6.48\n"
            "+# version 6.49\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 1
        assert changes[0]["component"] == "system/general"

    def test_raw_line_contains_diff_lines(self):
        """Test 6: raw_line field contains actual changed diff lines joined with newlines."""
        diff_text = (
            "--- a/config\n"
            "+++ b/config\n"
            "@@ -1,3 +1,4 @@\n"
            " /ip address\n"
            "+add address=10.0.0.1/24 interface=ether1\n"
            "-add address=192.168.1.1/24 interface=ether2\n"
        )
        changes = parse_diff_changes(diff_text)
        assert len(changes) == 1
        raw = changes[0]["raw_line"]
        assert "+add address=10.0.0.1/24 interface=ether1" in raw
        assert "-add address=192.168.1.1/24 interface=ether2" in raw
        # Lines are joined with newlines
        assert "\n" in raw
