import logging


def transaction_verify(history, transaction, reward=False):
    """
    transaction_verify()

    This function verifies a transaction in several ways.

    :param history: <History Object> The history object to use.
    :param transaction: <Transaction> The transaction to check.
    :param reward: <boolean> Whether this is a reward transaction or not.

    :return: <boolean> Whether the transaction passes verification.
    """

    if history.get_transaction(transaction.get_uuid()) is not None:
        # The transaction already exists.
        logging.info("Bad transaction: transaction exists")
        return False

    # Check input coins
    bad_transaction = False
    for coin in transaction.get_inputs():
        found_coin = history.get_coin(coin.get_uuid())
        if found_coin is None:
            # The input coin does not exist.
            logging.info("Bad transaction: input coins do not exist")
            bad_transaction = True
            break

        if found_coin.get_value() != coin.get_value() or found_coin.get_transaction_id() != coin.get_transaction_id():
            # The coin does not match what we have in history.
            logging.info("Bad transaction: input coins do not match")

            bad_transaction = True
            break

    if bad_transaction:
        return False

    # Check output coins
    for recipient in transaction.get_all_output_recipient_coins():
        if bad_transaction:
            break

        for coin in transaction.get_all_output_recipient_coins()[recipient]:
            if history.get_coin(coin.get_uuid()):
                logging.error('Fatal Error: This transaction contains an output coin that already exists: ' + str(transaction))
                bad_transaction = True
                break

    if bad_transaction:
        return False

    if transaction.verify(history):
        # The transaction looks proper. Remove inputs and add outputs to history.
        for coin in transaction.get_inputs():
            history.remove_coin(coin.get_uuid())

        for coin in transaction.get_all_output_coins():
            history.add_coin(coin)

        # Add transaction to queue and history.
        history.add_transaction(transaction)
        return True

    logging.info("Bad transaction: built in verification failed")
    return False