import ipaddress


def is_valid_ipv6(address):
    """Check an IPv6 address for validity"""
    try:
        ip = ipaddress.ip_address(address)
    except ValueError:
        return False
    if not isinstance(ip, ipaddress.IPv6Address):
        return False

    error = None
    warning = None
    if ip.is_loopback:
        error = "loopback address"
    elif ip.is_multicast:
        error = "multicast address"
    elif ip.is_link_local:
        error = "link-local address"
    elif ip.is_site_local:
        error = "deprecated site-local address"
    elif ip.is_unspecified:
        error = "unspecified address"
    elif ip.teredo:
        warning = "Teredo address"
    elif ip.sixtofour:
        warning = "6to4 address"
    elif ip.ipv4_mapped:
        warning = "mapped IPv4 address"
    elif ip in ipaddress.IPv6Network("2001:10::/28"):
        warning = "ORCHID address"
    elif ip in ipaddress.IPv6Network("2001:20::/28"):
        warning = "ORCHIDv2 address"
    elif ip in ipaddress.IPv6Network("2001:db8::/32"):
        warning = "documentation address"
    elif ip in ipaddress.IPv6Network("2001::/23"):
        warning = "IETF protocol address"
    elif ip in ipaddress.IPv6Network("100::/64"):
        error = "discard address"
    elif ip.is_private:
        error = "private address"
    elif ip.is_reserved:
        error = "reserved address"
    elif not ip.is_global:  # pragma: no cover
        # Should not be reached.  The selections above cover all bases.
        warning = "unknown address type"

    if error:
        print("*** Error: {} is a {}".format(address, error))
        return False
    if warning:
        print("*** Warning: {} is a {}".format(address, warning))
    return True