from alaya.packages.eth_utils import (
    is_bytes,
    is_hex,
    is_integer,
    is_string,
    is_text,
    remove_0x_prefix,
)


def is_predefined_block_number(value):
    if is_text(value):
        value_text = value
    elif is_bytes(value):
        # `value` could either be random bytes or the utf-8 encoding of
        # one of the words in: {"latest", "pending", "earliest"}
        # We cannot decode the bytes as utf8, because random bytes likely won't be valid.
        # So we speculatively decode as 'latin-1', which cannot fail.
        value_text = value.decode('latin-1')
    elif is_integer(value):
        return False
    else:
        raise TypeError("unrecognized block reference: %r" % value)

    return value_text in {"latest", "pending", "earliest"}


def is_hex_encoded_block_hash(value):
    if not is_string(value):
        return False
    return len(remove_0x_prefix(value)) == 64 and is_hex(value)


def is_hex_encoded_block_number(value):
    if not is_string(value):
        return False
    elif is_hex_encoded_block_hash(value):
        return False
    try:
        value_as_int = int(value, 16)
    except ValueError:
        return False
    return 0 <= value_as_int < 2**256


def select_method_for_block_identifier(value, if_hash, if_number, if_predefined):
    if is_predefined_block_number(value):
        return if_predefined
    elif isinstance(value, bytes):
        return if_hash
    elif is_hex_encoded_block_hash(value):
        return if_hash
    elif is_integer(value) and (0 <= value < 2**256):
        return if_number
    elif is_hex_encoded_block_number(value):
        return if_number
    else:
        raise ValueError(
            "Value did not match any of the recognized block identifiers: {0}".format(value)
        )
