package org.cloudfoundry.promregator.endpoint;

import java.time.Duration;
import java.util.List;

import org.cloudfoundry.promregator.fetcher.MetricsFetcher;
import org.cloudfoundry.promregator.scanner.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;

import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Gauge;
import io.prometheus.client.exporter.common.TextFormat;

/**
 * A spring-framework HTTP REST-server endpoint, compliant to the specification of a Prometheus text (!) metrics endpoint,
 * whose data is being backed by a set of further Prometheus metrics endpoints run on one or several CF apps. 
 *
 */
@RestController
@Scope(value=WebApplicationContext.SCOPE_REQUEST) // see also https://github.com/promregator/promregator/issues/51
@RequestMapping(EndpointConstants.ENDPOINT_PATH_SINGLE_ENDPOINT_SCRAPING)
public class MetricsEndpoint extends AbstractMetricsEndpoint {
	private static final Logger log = LoggerFactory.getLogger(MetricsEndpoint.class);

	@GetMapping(produces=TextFormat.CONTENT_TYPE_004)
	public ResponseEntity<String> getMetrics() {
		if (this.isLoopbackRequest()) {
			throw new LoopbackScrapingDetectedException("Erroneous Loopback Scraping request detected");
		}
		try {
			String result = this.handleRequest(null, null /* no filtering intended */);
			return new ResponseEntity<>(result, HttpStatus.OK);
		} catch (ScrapingException e) {
			return new ResponseEntity<>(e.toString(), HttpStatus.SERVICE_UNAVAILABLE);
		}
	}

	@Override
	protected boolean isIncludeGlobalMetrics() {
		return true;
	}

	@Override
	protected boolean isLabelEnrichmentSuppressable() {
		/*
		 * We may have metrics of multiple different Cloud Foundry instances in our response. 
		 * If label enrichment would be suppressed, this could mix up all the data.
		 * That is why we must prevent that label enrichment is suppressed (hence, answering "false").
		 */
		return false;
	}
	

	/* (non-Javadoc)
	 * @see org.cloudfoundry.promregator.endpoint.AbstractMetricsEndpoint#createMetricsFetchers(java.util.List)
	 */
	@Override
	protected List<MetricsFetcher> createMetricsFetchers(List<Instance> instanceList) {
		if (instanceList.size() > 20) {
			log.warn(String.format("You are using Single Endpoint Scraping with %d (>20) active targets; to improve scalability it is recommended to switch to Single Target Scraping", instanceList.size()));
		}

		return super.createMetricsFetchers(instanceList);
	}

	@Override
	protected void handleScrapeDuration(CollectorRegistry requestRegistry, Duration duration) {
		/* Note:
		 * The metric in this method intends to describe how much time has passed 
		 * for the *entire* scraping process. It's not the intention of this metric
		 * to drill-down to each scraping request.
		 * That is why it does not have additional labels, i.e. it does not have labels
		 * which are depending on the target.
		 * 
		 * See also the description of "promregator_scrape_duration_seconds" in
		 * https://github.com/promregator/promregator/blob/4b2ca289b624328e7e0b3838112e31a908a55c58/docs/enrichment.md
		 */
		Gauge scrapeDuration = Gauge.build("promregator_scrape_duration_seconds", "Duration in seconds indicating how long scraping of all metrics took")
				.register(requestRegistry);
		
		scrapeDuration.set(duration.toMillis() / 1000.0);
	}

}