class BesuCommand implements DefaultCommandValues, Runnable {

  private PrivacyParameters privacyParameters() {

    CommandLineUtils.checkOptionDependencies(
        logger,
        commandLine,
        "--privacy-enabled",
        !isPrivacyEnabled,
        asList(
            "--privacy-url",
            "--privacy-public-key-file",
            "--privacy-multi-tenancy-enabled",
            "--privacy-tls-enabled"));

    checkPrivacyTlsOptionsDependencies();

    final PrivacyParameters.Builder privacyParametersBuilder = new PrivacyParameters.Builder();
    if (isPrivacyEnabled) {
      final String errorSuffix = "cannot be enabled with privacy.";
      if (syncMode == SyncMode.FAST) {
        throw new ParameterException(commandLine, String.format("%s %s", "Fast sync", errorSuffix));
      }
      if (isPruningEnabled()) {
        throw new ParameterException(commandLine, String.format("%s %s", "Pruning", errorSuffix));
      }

      if (isPrivacyMultiTenancyEnabled
          && !jsonRpcConfiguration.isAuthenticationEnabled()
          && !webSocketConfiguration.isAuthenticationEnabled()) {
        throw new ParameterException(
            commandLine,
            "Privacy multi-tenancy requires either http authentication to be enabled or WebSocket authentication to be enabled");
      }

      privacyParametersBuilder.setEnabled(true);
      privacyParametersBuilder.setEnclaveUrl(privacyUrl);
      privacyParametersBuilder.setMultiTenancyEnabled(isPrivacyMultiTenancyEnabled);
      privacyParametersBuilder.setOnchainPrivacyGroupsEnabled(isOnchainPrivacyGroupEnabled);

      if (isPrivacyMultiTenancyEnabled && isOnchainPrivacyGroupEnabled) {
        throw new ParameterException(
            commandLine,
            "Privacy multi-tenancy and onchain privacy groups cannot be used together");
      }

      final boolean hasPrivacyPublicKey = privacyPublicKeyFile != null;
      if (hasPrivacyPublicKey && !isPrivacyMultiTenancyEnabled) {
        try {
          privacyParametersBuilder.setEnclavePublicKeyUsingFile(privacyPublicKeyFile);
        } catch (final IOException e) {
          throw new ParameterException(
              commandLine, "Problem with privacy-public-key-file: " + e.getMessage(), e);
        } catch (final IllegalArgumentException e) {
          throw new ParameterException(
              commandLine, "Contents of privacy-public-key-file invalid: " + e.getMessage(), e);
        }
      } else if (hasPrivacyPublicKey) {
        throw new ParameterException(
            commandLine, "Privacy multi-tenancy and privacy public key cannot be used together");
      } else if (!isPrivacyMultiTenancyEnabled) {
        throw new ParameterException(
            commandLine, "Please specify Enclave public key file path to enable privacy");
      }

      if (Wei.ZERO.compareTo(minTransactionGasPrice) < 0) {
        // if gas is required, cannot use random keys to sign private tx
        // ie --privacy-marker-transaction-signing-key-file must be set
        if (privacyMarkerTransactionSigningKeyPath == null) {
          throw new ParameterException(
              commandLine,
              "Not a free gas network. --privacy-marker-transaction-signing-key-file must be specified and must be a funded account. Private transactions cannot be signed by random (non-funded) accounts in paid gas networks");
        }
      }

      if (!Address.PRIVACY.equals(privacyPrecompiledAddress)) {
        logger.warn(
            "--privacy-precompiled-address option is deprecated. This address is derived, based on --privacy-onchain-groups-enabled.");
      }

      privacyParametersBuilder.setPrivateKeyPath(privacyMarkerTransactionSigningKeyPath);
      privacyParametersBuilder.setStorageProvider(
          privacyKeyStorageProvider(keyValueStorageName + "-privacy"));
      if (isPrivacyTlsEnabled) {
        privacyParametersBuilder.setPrivacyKeyStoreFile(privacyKeyStoreFile);
        privacyParametersBuilder.setPrivacyKeyStorePasswordFile(privacyKeyStorePasswordFile);
        privacyParametersBuilder.setPrivacyTlsKnownEnclaveFile(privacyTlsKnownEnclaveFile);
      }
      privacyParametersBuilder.setEnclaveFactory(new EnclaveFactory(vertx));
    } else {
      if (anyPrivacyApiEnabled()) {
        logger.warn("Privacy is disabled. Cannot use EEA/PRIV API methods when not using Privacy.");
      }
    }

    final PrivacyParameters privacyParameters = privacyParametersBuilder.build();

    if (isPrivacyEnabled) {
      preSynchronizationTaskRunner.addTask(
          new PrivateDatabaseMigrationPreSyncTask(privacyParameters, migratePrivateDatabase));
    }

    return privacyParameters;
  }

  public  BesuCommand(
      final Logger logger,
      final Supplier<RlpBlockImporter> rlpBlockImporter,
      final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
      final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
      final RunnerBuilder runnerBuilder,
      final BesuController.Builder controllerBuilderFactory,
      final BesuPluginContextImpl besuPluginContext,
      final Map<String, String> environment);
  @VisibleForTesting protected  BesuCommand(
      final Logger logger,
      final Supplier<RlpBlockImporter> rlpBlockImporter,
      final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
      final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
      final RunnerBuilder runnerBuilder,
      final BesuController.Builder controllerBuilderFactory,
      final BesuPluginContextImpl besuPluginContext,
      final Map<String, String> environment,
      final StorageServiceImpl storageService,
      final SecurityModuleServiceImpl securityModuleService);

}