#!/usr/bin/env python3
"""
nip.io URL generation script

This script given an IP address will give correct representation of URLs you
could use for the nip.io DNS resolver.

Example:

    $ ./nipio 10.22.33.44 mygreatapp

    IP 10.22.33.44
    ==================
    NIP_plain     http://mygreatapp-10.22.33.44.nip.io
    NIP_plain_TLS https://mygreatapp-10.22.33.44.nip.io
    NIP_dash      http://mygreatapp-10-22-33-44.nip.io
    NIP_dash_TLS  https://mygreatapp-10-22-33-44.nip.io
    # Uppercase hex
    NIP_hex       http://MYGREATAPP-0A16212C.nip.io
    NIP_hex_TLS   https://MYGREATAPP-0A16212C.nip.io
    # Lowercase hex
    NIP_hex       http://mygreatapp-0a16212c.nip.io
    NIP_hex_TLS   https://mygreatapp-0a16212c.nip.io
    # Uppercase dash
    NIP_dash      http://MYGREATAPP-10-22-33-44.nip.io
    NIP_dash_TLS  https://MYGREATAPP-10-22-33-44.nip.io
    # Lowercase dash
    NIP_dash      http://mygreatapp-10-22-33-44.nip.io
    NIP_dash_TLS  https://mygreatapp-10-22-33-44.nip.io
    # NOT implemented at this time on nip.io
    # does not work, but will look to change that :)
    NIP_B36       http://mygreatapp-c8slxm.nip.io
    NIP_B36_TLS   https://mygreatapp-c8slxm.nip.io
"""

import ipaddress
import socket
import sys


def base36encode(number: int) -> str:
    """Encode the int using Base36 and return the encoded string."""
    if not isinstance(number, int):
        raise TypeError("number must be an integer")
    if number < 0:
        raise ValueError("number must be positive")

    alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
    base36 = ""

    while number:
        number, i = divmod(number, 36)
        base36 = alphabet[i] + base36

    return base36 or alphabet[0]


def base36decode(number: str) -> int:
    """Decode the Base36 encoded string and return the decoded int."""
    return int(number, 36)


if len(sys.argv) < 2:
    sys.exit(f"Usage: {sys.argv[0]} <IP address> <optional app name>")
if len(sys.argv) > 2:
    app_name = f"{sys.argv[2]}-"
else:
    app_name = ""

try:
    ip_addr = ipaddress.ip_address(sys.argv[1])
except ValueError as err:
    sys.exit(err)

b36_name = base36encode(int(ip_addr))


def ip_as_hex(ip_string: str) -> str:
    """Return a hexadecimal representation of the IP address."""
    return socket.inet_aton(ip_string).hex()


ip = sys.argv[1]
ip_dash = sys.argv[1].replace(".", "-")
ip_hex = ip_as_hex(sys.argv[1])

output = f"""
IP {ip}
==================
NIP_plain     http://{app_name.lower()}{ip}.nip.io
NIP_plain_TLS https://{app_name.lower()}{ip}.nip.io
NIP_dash      http://{app_name.lower()}{ip_dash}.nip.io
NIP_dash_TLS  https://{app_name.lower()}{ip_dash}.nip.io
# Uppercase hex
NIP_hex       http://{app_name.upper()}{ip_hex.upper()}.nip.io
NIP_hex_TLS   https://{app_name.upper()}{ip_hex.upper()}.nip.io
# Lowercase hex
NIP_hex       http://{app_name.lower()}{ip_hex.lower()}.nip.io
NIP_hex_TLS   https://{app_name.lower()}{ip_hex.lower()}.nip.io
# Uppercase dash
NIP_dash      http://{app_name.upper()}{ip_dash}.nip.io
NIP_dash_TLS  https://{app_name.upper()}{ip_dash}.nip.io
# Lowercase dash
NIP_dash      http://{app_name.lower()}{ip_dash}.nip.io
NIP_dash_TLS  https://{app_name.lower()}{ip_dash}.nip.io
"""
# NOT implemented at this time on nip.io
# does not work, but will look to change that :)
# NIP_B36       http://{app_name.lower()}{b36_name}.nip.io
# NIP_B36_TLS   https://{app_name.lower()}{b36_name}.nip.io
print(output)
