#!/usr/bin/env python3
"""
VPN Network Calculator для ViPNet-подобных конфигураций.
Рассчитывает адреса узлов и формирует VPN.txt.
"""

import ipaddress
import re
import sys


def parse_network(prompt: str) -> ipaddress.IPv4Network:
    while True:
        raw = input(prompt).strip()
        try:
            net = ipaddress.IPv4Network(raw, strict=False)
            return net
        except ValueError:
            print(f"  ✗ Неверный формат. Введите сеть в виде x.x.x.x/prefix (например, 192.168.10.128/27)")


def mask_str(net: ipaddress.IPv4Network) -> str:
    return str(net.netmask)


def prefix_str(net: ipaddress.IPv4Network) -> str:
    return f"/{net.prefixlen}"


def host(net: ipaddress.IPv4Network, offset: int) -> str:
    """Возвращает хост по смещению от начала сети (0 = network address)."""
    return str(net.network_address + offset)


def generate_vpn(co_net: ipaddress.IPv4Network,
                 branch_net: ipaddress.IPv4Network,
                 inet_net: ipaddress.IPv4Network) -> str:

    co_pref     = prefix_str(co_net)
    co_mask     = mask_str(co_net)
    br_pref     = prefix_str(branch_net)
    br_mask     = mask_str(branch_net)
    inet_pref   = prefix_str(inet_net)
    inet_mask   = mask_str(inet_net)

    # Маски, используемые в конфиге
    masks_used = {}
    for net in (co_net, branch_net, inet_net):
        masks_used[net.prefixlen] = mask_str(net)

    masks_lines = "\n".join(
        f"/{pref} — {mask}" for pref, mask in sorted(masks_used.items())
    )

    # ЦО хосты
    co_coord   = host(co_net, 1)   # Net1-coord (RootCoord)
    co_adminCA = host(co_net, 2)   # AdminCA
    co_operCA  = host(co_net, 3)   # OperCA
    co_open    = host(co_net, 4)   # Net1-Open  (шлюз ЦО во вн. сеть)

    # Филиал хосты
    br_coord   = host(branch_net, 1)  # Net2-coord (SubCoord)
    br_client  = host(branch_net, 2)  # net2-client

    # Интернет хосты
    inet_root  = host(inet_net, 1)   # внешний IP RootCoord
    inet_sub   = host(inet_net, 2)   # внешний IP SubCoord

    lines = []

    # ── Заголовок: маски ──────────────────────────────────────────────────────
    lines.append(f"Маски: {masks_lines}\n")

    # ── Сети ─────────────────────────────────────────────────────────────────
    lines.append(f"ЦО: {co_net.network_address} {co_pref}")
    lines.append(f"Филиал: {branch_net.network_address} {br_pref}")
    lines.append(f"Интернет: {inet_net.network_address} {inet_pref}")
    lines.append("")

    # ── Координатор ЦО ───────────────────────────────────────────────────────
    lines.append(f"Координатор  Net1-coord(RootCoord): {co_coord}   {co_pref}           ")
    lines.append(co_mask)
    lines.append(f"внеш: {inet_root} {inet_pref}")
    lines.append(f"шлюз: {inet_sub}")
    lines.append("")

    lines.append(f"AdminCA: {co_adminCA}  {co_pref}")
    lines.append(co_mask)
    lines.append(f"шлюз:  {co_open}  (* после настройки RootCoord сменить на {co_coord})")
    lines.append("")

    lines.append(f"OperCA: {co_operCA} {co_pref}")
    lines.append(co_mask)
    lines.append(f"шлюз: {co_coord}")
    lines.append("")

    lines.append(f"Net1-Open: {co_open} {co_pref}")
    lines.append(co_mask)
    lines.append(f"шлюз:  {co_adminCA}  (* после настройки RootCoord сменить на {co_coord})")
    lines.append("------------------------")

    # ── Координатор Филиал ───────────────────────────────────────────────────
    lines.append(f"Координатор филиал Net2-coord (subcoord): {br_coord} {br_pref}")
    lines.append(br_mask)
    lines.append(f"внеш: {inet_sub} {inet_pref}")
    lines.append(f"шлюз: {inet_root}")
    lines.append("")

    lines.append(f"net2-client: {br_client} {br_pref}")
    lines.append(br_mask)
    lines.append(f"шлюз: {br_coord}")
    lines.append("-------------------------------------------------")

    # ── Интерфейсы ───────────────────────────────────────────────────────────
    lines.append("интерфейсы")
    lines.append("RootCoord:")
    lines.append(f"eth0: {inet_root} ")
    lines.append(inet_mask)
    lines.append(f"eth1: {co_coord}")
    lines.append(co_mask)
    lines.append("")
    lines.append("SubCoord:")
    lines.append(f"eth0: {inet_sub}")
    lines.append(inet_mask)
    lines.append(f"eth1: {br_coord}")
    lines.append(br_mask)
    lines.append("----------------------------------------------")

    return "\n".join(lines)


def main():
    print("=" * 52)
    print("  VPN Network Calculator")
    print("=" * 52)
    print("Введите три сети в формате x.x.x.x/prefix\n")

    co_net     = parse_network("Сеть ЦО        : ")
    branch_net = parse_network("Сеть Филиала   : ")
    inet_net   = parse_network("Сеть Интернет  : ")

    print()

    # Проверки минимального размера сетей
    warnings = []
    if co_net.num_addresses < 8:
        warnings.append(f"  ! Сеть ЦО слишком маленькая ({co_net.prefixlen}), нужно хотя бы /29")
    if branch_net.num_addresses < 4:
        warnings.append(f"  ! Сеть Филиала слишком маленькая ({branch_net.prefixlen}), нужно хотя бы /30")
    if inet_net.num_addresses < 4:
        warnings.append(f"  ! Сеть Интернет слишком маленькая ({inet_net.prefixlen}), нужно хотя бы /30")

    if warnings:
        print("Предупреждения:")
        for w in warnings:
            print(w)
        print()

    content = generate_vpn(co_net, branch_net, inet_net)

    out_path = "VPN.txt"
    with open(out_path, "w", encoding="utf-8") as f:
        # BOM для совместимости с Windows Notepad
        f.write("\ufeff")
        f.write(content)

    print(content)
    print()
    print(f"✓ Файл сохранён: {out_path}")


if __name__ == "__main__":
    main()
