/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
package org.apache.ambari.server.controller.logging;

import java.util.List;

import jakarta.inject.Inject;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.State;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;


public class LoggingRequestHelperFactoryImpl implements LoggingRequestHelperFactory {

  private static final Logger LOG = Logger.getLogger(LoggingRequestHelperFactoryImpl.class);

  private static final String LOGSEARCH_PROPERTIES_CONFIG_TYPE_NAME = "logsearch-properties";

  private static final String LOGSEARCH_SERVICE_NAME = "LOGSEARCH";

  private static final String LOGSEARCH_SERVER_COMPONENT_NAME = "LOGSEARCH_SERVER";

  private static final String LOGSEARCH_HTTP_PORT_PROPERTY_NAME = "logsearch.http.port";

  private static final String LOGSEARCH_HTTPS_PORT_PROPERTY_NAME = "logsearch.https.port";

  private static final String LOGSEARCH_UI_PROTOCOL = "logsearch.protocol";

  private static final String LOGSEARCH_HTTPS_PROTOCOL_VALUE = "https";

  @Inject
  private Configuration ambariServerConfiguration;

  @Override
  public LoggingRequestHelper getHelper(AmbariManagementController ambariManagementController, String clusterName) {

    if (ambariServerConfiguration == null) {
      LOG.error("Ambari Server configuration object not available, cannot create request helper");
      return null;
    }

    Clusters clusters =
      ambariManagementController.getClusters();

    try {
      final LoggingRequestHelperImpl loggingRequestHelper;
      Cluster cluster = clusters.getCluster(clusterName);
      if (cluster != null) {
        final String logSearchHostName;
        final String logSearchPortNumber;
        final String logSearchProtocol;
        if (StringUtils.isNotBlank(ambariServerConfiguration.getLogSearchPortalExternalAddress())) {
          loggingRequestHelper = new LoggingRequestHelperImpl(null, null, null,
            ambariManagementController.getCredentialStoreService(), cluster, ambariServerConfiguration.getLogSearchPortalExternalAddress());
        } else {
          boolean isLogSearchEnabled =
            cluster.getServices().containsKey(LOGSEARCH_SERVICE_NAME);

          if (!isLogSearchEnabled) {
            // log search not enabled, just return null, since no helper impl is necessary
            return null;
          }

          Config logSearchEnvConfig =
            cluster.getDesiredConfigByType(LOGSEARCH_PROPERTIES_CONFIG_TYPE_NAME);

          List<ServiceComponentHost> listOfMatchingHosts =
            cluster.getServiceComponentHosts(LOGSEARCH_SERVICE_NAME, LOGSEARCH_SERVER_COMPONENT_NAME);


          if (listOfMatchingHosts.size() == 0) {
            LOG.warn("No matching LOGSEARCH_SERVER instances found, this may indicate a deployment problem.  Please verify that LogSearch is deployed and running.");
            return null;
          }

          if (listOfMatchingHosts.size() > 1) {
            LOG.warn("More than one LOGSEARCH_SERVER instance found, this may be a deployment error.  Only the first LOGSEARCH_SERVER instance will be used.");
          }

          ServiceComponentHost serviceComponentHost =
            listOfMatchingHosts.get(0);

          if (serviceComponentHost.getState() != State.STARTED) {
            // if the LOGSEARCH_SERVER is not started, don't attempt to connect
            return null;
          }

          logSearchHostName = serviceComponentHost.getHostName();

          logSearchProtocol =
            logSearchEnvConfig.getProperties().get(LOGSEARCH_UI_PROTOCOL);

          logSearchPortNumber = LOGSEARCH_HTTPS_PROTOCOL_VALUE.equalsIgnoreCase(logSearchProtocol)
            ? logSearchEnvConfig.getProperties().get(LOGSEARCH_HTTPS_PORT_PROPERTY_NAME)
            : logSearchEnvConfig.getProperties().get(LOGSEARCH_HTTP_PORT_PROPERTY_NAME);

          loggingRequestHelper = new LoggingRequestHelperImpl(logSearchHostName, logSearchPortNumber, logSearchProtocol,
            ambariManagementController.getCredentialStoreService(), cluster, null);
        }
        // set configured timeouts for the Ambari connection to the LogSearch Portal service
        loggingRequestHelper.setLogSearchConnectTimeoutInMilliseconds(ambariServerConfiguration.getLogSearchPortalConnectTimeout());
        loggingRequestHelper.setLogSearchReadTimeoutInMilliseconds(ambariServerConfiguration.getLogSearchPortalReadTimeout());
        return loggingRequestHelper;
      }
    } catch (AmbariException ambariException) {
      LOG.error("Error occurred while trying to obtain the cluster, cluster name = " + clusterName, ambariException);
    }


    return null;
  }

  /**
   * Package-level setter to facilitate simpler unit testing
   *
   * @param ambariServerConfiguration the Ambari Server configuration properties
   */
  void setAmbariServerConfiguration(Configuration ambariServerConfiguration) {
    this.ambariServerConfiguration = ambariServerConfiguration;
  }
}
