import os
import sys
from pathlib import Path

# NOTE: we could find a way to use python's builtin ConfigParser library to read/write INI files, however it'd need
#   some tweaking as it doesn't deal with multiple entries with the same name, which Wireguard makes use of.
# see: https://docs.python.org/3/library/configparser.html#mapping-protocol-access
# and: https://stackoverflow.com/questions/15848674/how-to-configparse-a-file-keeping-multiple-values-for-identical-keys
# and: https://www.reddit.com/r/learnpython/comments/37ihgh/how_to_handle_multiple_items_with_same_name_in/
# and: https://pastebin.com/cZ8SzbXK


def check_privileges():
    if not os.geteuid() == 0:
        print("error: you have to run as root.")
        sys.exit(3)


def ini_after_equal(s: str) -> str:
    idx: int = s.find("=")
    after_equal: str = s[idx + 1 :].strip().replace("\n", "")
    return after_equal


def write_protected(fp: Path, content: str) -> None:
    # create parent dir if not exists
    makedir_protected(fp.parent)

    # default umask is 0o22 which turns off write permission of group and others
    os.umask(0)

    descriptor = os.open(
        path=fp,
        flags=(
            os.O_WRONLY  # access mode: write only
            | os.O_CREAT  # create if not exists
            | os.O_TRUNC  # truncate the file to zero
        ),
        mode=0o600,
    )

    with open(descriptor, "w") as fh:
        fh.write(content)


def makedir_protected(path: Path) -> None:
    # create dir if not exists
    # TODO should set the mode in case the directory exists, but it's got a
    # different mode?
    if not os.path.exists(path) and not os.path.isdir(path):
        # default umask is 0o22 which turns off write permission of group and others
        os.umask(0)
        os.makedirs(path)


def rm_tree(p: Path):
    # recursively remove a directory.
    for child in p.iterdir():
        if child.is_file() or child.is_symlink():
            child.unlink()
        else:
            rm_tree(child)
    p.rmdir()


def rm_dir_if_empty(p: Path):
    # removes a directory if empty
    if not p.is_dir():
        raise ValueError("Path is not a directory: '{p}'")
    if not any(p.iterdir()):
        p.rmdir()


# def parse_conf(conf_fp: Path) -> Tuple[List[Interface], List[Peer]]:
#     with open(conf_fp, 'r') as fd:
#         conf_lines = fd.readlines()
#
#     # init vars
#     interfaces: List[Interface] = []
#     peers: List[Peer] = []
#
#     # parsing
#     in_peer_section = False
#     in_interface_section = False
#     # accumulator
#     acc: Dict[str, Any] = {}
#
#     conf_lines_cleaned = [line.replace('\n', '').strip()  # newline chars & strip
#                           for line in conf_lines]
#     conf_lines_cleaned = [line
#                           for line in conf_lines_cleaned
#                           if line and (not line.startswith('#') or line.startswith('# Name'))]# empty lines & comments
#
#     for line in conf_lines_cleaned:
#         # init
#         if not in_interface_section and not in_peer_section:
#             if line.startswith("[Interface]"):
#                 in_interface_section = True
#
#             elif line.startswith("[Peer]"):
#                 in_peer_section = True
#
#         # parse an interface section
#         elif in_interface_section:
#             # stop condition: re-entering an [Interface] section
#             if line.startswith('[Interface]'):
#                 # build previous interface from accumulator
#                 interfaces.append(Interface.from_dict(cast(InterfaceDict, acc)))
#                 # reset accumulator
#                 acc = {}
#                 # update boolean flags
#                 in_peer_section = False
#                 in_interface_section = True
#
#             # stop condition: entering [Peer] section
#             elif line.startswith('[Peer]'):
#                 # build previous interface from accumulator
#                 interfaces.append(Interface.from_dict(cast(InterfaceDict, acc)))
#                 # reset accumulator
#                 acc = {}
#                 # update boolean flags
#                 in_peer_section = True
#                 in_interface_section = False
#
#             else:
#                 # update accumulator with [Interface] section line
#                 acc = Interface.parse_section_line(acc, line)
#
#         # parse a peer section
#         elif in_peer_section:
#             # stop condition: entering an [Interface] section
#             if line.startswith('[Interface]'):
#                 # build previous peer from accumulator
#                 peers.append(Peer.from_dict(cast(PeerDict, acc)))
#                 # reset accumulator
#                 acc = {}
#                 # update boolean flags
#                 in_peer_section = False
#                 in_interface_section = True
#
#             # stop condition: entering [Peer] section
#             elif line.startswith('[Peer]'):
#                 # build previous peer from accumulator
#                 peers.append(Peer.from_dict(cast(PeerDict, acc)))
#                 # reset accumulator
#                 acc = {}
#                 # update boolean flags
#                 in_peer_section = True
#                 in_interface_section = False
#
#             else:
#                 # update accumulator with [Peer] section line
#                 acc = Peer.parse_section_line(acc, line)
#
#     if in_interface_section:
#         interfaces.append(Interface.from_dict(cast(InterfaceDict, acc)))
#
#     elif in_peer_section:
#         peers.append(Peer.from_dict(cast(PeerDict, acc)))
#
#     return (interfaces, peers)
