"""
This Ansible filter plugin parses `nordvpn meshnet peer list` output into peer hostnames.
"""

from __future__ import annotations

from dotenv import load_dotenv

load_dotenv(override=False)

DOCUMENTATION = """
name: nordvpn_meshnet_peer_hostnames
short_description: Parse `nordvpn meshnet peer list` output into a list of peer hostnames.
version_added: "1.2.0"
description:
    - Parse the plain-text output of `nordvpn meshnet peer list` and return the Meshnet
      hostname (e.g. arpan.rec-andes.nord) of every peer in the "Local Peers" and
      "External Peers" sections, excluding the local device's own entry under "This device".
options:
    _input:
        description:
            - The stdout of `nordvpn meshnet peer list`.
        required: true
        type: str
"""

EXAMPLES = """
- name: Get Meshnet peer hostnames excluding this device
  ansible.builtin.debug:
      msg: "{{ nordvpn_meshnet_peer_list_result.stdout
          | nordvpn_meshnet_peer_hostnames }}"
"""

RETURN = r"""
_value:
    description: A list of peer Meshnet hostnames, excluding the local device.
    type: list
    elements: str
"""

_SECTION_HEADERS = ("This device:", "Local Peers:", "External Peers:")


def _parse_blocks(lines: list[str]) -> list[dict[str, str]]:
    """
    Split a section's lines into peer blocks (separated by blank lines) and parse each
    block's "Key: Value" lines into a dictionary.
    """
    blocks: list[dict[str, str]] = []
    current: dict[str, str] = {}
    for raw_line in lines:
        line = raw_line.strip()
        if not line:
            if current:
                blocks.append(current)
                current = {}
            continue
        if ":" not in line:
            continue
        key, _, value = line.partition(":")
        current[key.strip()] = value.strip()
    if current:
        blocks.append(current)
    return blocks


def nordvpn_meshnet_peer_hostnames(peer_list_stdout: str) -> list[str]:
    """
    Parse `nordvpn meshnet peer list` stdout and return every peer's Meshnet hostname,
    excluding the local device ("This device" section).
    """
    lines_by_section: dict[str, list[str]] = {header[:-1]: [] for header in _SECTION_HEADERS}
    current_section = None

    for line in peer_list_stdout.splitlines():
        stripped = line.strip()
        if stripped in _SECTION_HEADERS:
            current_section = stripped[:-1]
            continue
        if current_section is not None:
            lines_by_section[current_section].append(line)

    self_hostnames = {block.get("Hostname") for block in _parse_blocks(lines_by_section["This device"])}

    peer_hostnames: list[str] = []
    for section in ("Local Peers", "External Peers"):
        for block in _parse_blocks(lines_by_section[section]):
            hostname = block.get("Hostname")
            if hostname and hostname not in self_hostnames:
                peer_hostnames.append(hostname)

    return peer_hostnames


class FilterModule:  # pylint: disable=too-few-public-methods
    """
    A filter plugin for Ansible.
    """

    def filters(self) -> dict[str, object]:
        """
        Return a dictionary mapping filter names to functions.
        """
        return {
            "nordvpn_meshnet_peer_hostnames": nordvpn_meshnet_peer_hostnames,
        }
