/*
 * Copyright ConsenSys AG.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package org.hyperledger.besu.ethereum.mainnet;

import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Log;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.OperationTracer;

import java.util.List;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;

/** Processes transactions. */
public interface TransactionProcessor {

  /** A transaction processing result. */
  interface Result {

    /** The status of the transaction after being processed. */
    enum Status {

      /** The transaction was invalid for processing. */
      INVALID,

      /** The transaction was successfully processed. */
      SUCCESSFUL,

      /** The transaction failed to be completely processed. */
      FAILED
    }

    /**
     * Return the logs produced by the transaction.
     *
     * <p>This is only valid when {@code TransactionProcessor#isSuccessful} returns {@code true}.
     *
     * @return the logs produced by the transaction
     */
    List<Log> getLogs();

    /**
     * Returns the status of the transaction after being processed.
     *
     * @return the status of the transaction after being processed
     */
    Status getStatus();

    /**
     * Returns the gas remaining after the transaction was processed.
     *
     * <p>This is only valid when {@code TransactionProcessor#isSuccessful} returns {@code true}.
     *
     * @return the gas remaining after the transaction was processed
     */
    long getGasRemaining();

    Bytes getOutput();

    /**
     * Returns whether or not the transaction was invalid.
     *
     * @return {@code true} if the transaction was invalid; otherwise {@code false}
     */
    default boolean isInvalid() {
      return getStatus() == Status.INVALID;
    }

    /**
     * Returns whether or not the transaction was successfully processed.
     *
     * @return {@code true} if the transaction was successfully processed; otherwise {@code false}
     */
    default boolean isSuccessful() {
      return getStatus() == Status.SUCCESSFUL;
    }

    /**
     * Returns the transaction validation result.
     *
     * @return the validation result, with the reason for failure (if applicable.)
     */
    ValidationResult<TransactionValidator.TransactionInvalidReason> getValidationResult();

    /**
     * Returns the reason why a transaction was reverted (if applicable).
     *
     * @return the revert reason.
     */
    Optional<Bytes> getRevertReason();
  }

  /**
   * Applies a transaction to the current system state.
   *
   * @param blockchain The current blockchain
   * @param worldState The current world state
   * @param blockHeader The current block header
   * @param transaction The transaction to process
   * @param miningBeneficiary The address which is to receive the transaction fee
   * @param blockHashLookup The {@link BlockHashLookup} to use for BLOCKHASH operations
   * @param isPersistingPrivateState Whether the resulting private state will be persisted
   * @param transactionValidationParams Validation parameters that will be used by the {@link
   *     TransactionValidator}
   * @return the transaction result
   * @see TransactionValidator
   * @see TransactionValidationParams
   */
  default Result processTransaction(
      final Blockchain blockchain,
      final WorldUpdater worldState,
      final ProcessableBlockHeader blockHeader,
      final Transaction transaction,
      final Address miningBeneficiary,
      final BlockHashLookup blockHashLookup,
      final Boolean isPersistingPrivateState,
      final TransactionValidationParams transactionValidationParams) {
    return processTransaction(
        blockchain,
        worldState,
        blockHeader,
        transaction,
        miningBeneficiary,
        OperationTracer.NO_TRACING,
        blockHashLookup,
        isPersistingPrivateState,
        transactionValidationParams);
  }

  /**
   * Applies a transaction to the current system state.
   *
   * @param blockchain The current blockchain
   * @param worldState The current world state
   * @param blockHeader The current block header
   * @param transaction The transaction to process
   * @param operationTracer The tracer to record results of each EVM operation
   * @param miningBeneficiary The address which is to receive the transaction fee
   * @param blockHashLookup The {@link BlockHashLookup} to use for BLOCKHASH operations
   * @param isPersistingPrivateState Whether the resulting private state will be persisted
   * @return the transaction result
   */
  default Result processTransaction(
      final Blockchain blockchain,
      final WorldUpdater worldState,
      final ProcessableBlockHeader blockHeader,
      final Transaction transaction,
      final Address miningBeneficiary,
      final OperationTracer operationTracer,
      final BlockHashLookup blockHashLookup,
      final Boolean isPersistingPrivateState) {
    return processTransaction(
        blockchain,
        worldState,
        blockHeader,
        transaction,
        miningBeneficiary,
        operationTracer,
        blockHashLookup,
        isPersistingPrivateState,
        new TransactionValidationParams.Builder().build());
  }

  Result processTransaction(
      Blockchain blockchain,
      WorldUpdater worldState,
      ProcessableBlockHeader blockHeader,
      Transaction transaction,
      Address miningBeneficiary,
      OperationTracer operationTracer,
      BlockHashLookup blockHashLookup,
      Boolean isPersistingPrivateState,
      TransactionValidationParams transactionValidationParams);
}
