#!/usr/bin/env python3
"""Original IPv4 address-planning lab. Python 3.11+, standard library only.

Real address arithmetic over fictional inputs. No sockets, cloud API, local
network changes, credentials or file writes. This is not a provider route engine.
"""
import argparse
import ipaddress
import json

SECOND_SUBNET = "10.24.1.128/25"
INCLUDE_SPECIFIC_ROUTE = True
CASES = ("inside", "outside", "overlap", "unaligned", "specific-route", "no-route", "capacity")


def network(cidr):
    return ipaddress.IPv4Network(cidr, strict=True)


def describe(cidr):
    block = network(cidr)
    return {"cidr": str(block), "prefix_bits": block.prefixlen,
            "address_bits": 32 - block.prefixlen, "total_addresses": block.num_addresses,
            "first": str(block.network_address), "last": str(block.broadcast_address)}


def choose_route(destination, routes):
    """Only distinct-prefix static routes; equal-length ambiguity is refused."""
    address = ipaddress.IPv4Address(destination)
    matches = [dict(route, prefix_bits=network(route["cidr"]).prefixlen)
               for route in routes if address in network(route["cidr"])]
    matches.sort(key=lambda route: route["prefix_bits"], reverse=True)
    if len(matches) > 1 and matches[0]["prefix_bits"] == matches[1]["prefix_bits"]:
        raise ValueError("Equal-prefix route selection needs a separate policy")
    return {"destination": str(address), "matching_routes": matches,
            "selected": matches[0] if matches else None,
            "connection_tested": False}


def run_case(name):
    if name in ("inside", "outside"):
        block = network("10.24.1.0/24")
        address = ipaddress.IPv4Address("10.24.1.10" if name == "inside" else "10.24.2.15")
        return {"case": name, "block": describe(str(block)), "address": str(address),
                "member": address in block, "within_plan": block.subnet_of(network("10.24.0.0/16")),
                "permission_established": False}
    if name == "overlap":
        first, second = network("10.24.1.0/24"), network(SECOND_SUBNET)
        overlaps = first.overlaps(second)
        common_first = max(int(first.network_address), int(second.network_address))
        common_last = min(int(first.broadcast_address), int(second.broadcast_address))
        shared = {"first": str(ipaddress.IPv4Address(common_first)),
                  "last": str(ipaddress.IPv4Address(common_last)),
                  "count": common_last - common_first + 1} if overlaps else None
        return {"case": name, "first": describe(str(first)), "second": describe(str(second)),
                "overlaps": overlaps, "shared": shared,
                "second_within_plan": second.subnet_of(network("10.24.0.0/16"))}
    if name == "unaligned":
        supplied = "10.24.1.7/24"
        try:
            network(supplied)
        except ValueError as error:
            return {"case": name, "supplied": supplied, "accepted": False, "reason": str(error),
                    "containing_block": str(ipaddress.IPv4Interface(supplied).network)}
        raise AssertionError("The unaligned network should be refused")
    if name in ("specific-route", "no-route"):
        routes = [{"cidr": "10.24.0.0/16", "next_hop": "internal-router"}]
        destination = "198.51.100.20"  # Documentation address; never contacted.
        if name == "specific-route":
            destination = "10.24.2.15"
            routes.append({"cidr": "0.0.0.0/0", "next_hop": "egress-router"})
            if INCLUDE_SPECIFIC_ROUTE:
                routes.append({"cidr": "10.24.2.0/24", "next_hop": "inspection-router"})
        return {"case": name, **choose_route(destination, routes)}
    if name == "capacity":
        block = describe("10.24.1.0/24")
        # Standard primary IPv4 subnet assumptions, not all provider range types.
        reservations = {"gcp_primary_ipv4": 4, "aws_standard_ipv4": 5, "azure_ipv4": 5}
        return {"case": name, "block": block,
                "profiles": {provider: {"reserved": count, "remaining_before_allocations": block["total_addresses"] - count}
                             for provider, count in reservations.items()},
                "actual_free_addresses": None, "vm_capacity_verified": False}
    raise ValueError(f"Unknown case: {name}")


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("case", choices=("compare",) + CASES, nargs="?", default="compare")
    args = parser.parse_args()
    print(json.dumps({"scope": "Offline IPv4 arithmetic and simplified route selection; no network or cloud operation",
                      "results": [run_case(name) for name in CASES if args.case in ("compare", name)]}, indent=2))


if __name__ == "__main__":
    main()
