/*
 * 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.camel.quarkus.performance.regression;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import org.apache.maven.artifact.versioning.ComparableVersion;
import tech.tablesaw.api.StringColumn;
import tech.tablesaw.api.Table;

/**
 * Provide a human readable performance regression report ready to be printed to
 * the console. For each camel-quarkus version, the report will print:
 * + The throughput for each measure in a category (JVM, Native) in a new column
 * + The percent increase throughput compared to the previous row in the same column
 */
public class PerformanceRegressionReport {

    private String duration;
    private TreeMap<ComparableVersion, Map<String, Double>> measuresPerVersion = new TreeMap<>();

    public PerformanceRegressionReport(String duration) {
        this.duration = duration;
    }

    public void setCategoryMeasureForVersion(String cqVersion, String category, double throughput) {
        ComparableVersion version = new ComparableVersion(cqVersion);
        measuresPerVersion.computeIfAbsent(version, k -> new HashMap<>()).put(category, throughput);
    }

    public String printAll() {
        Table table = Table.create("Camel Quarkus Throughput Performance Increase Compared to Previous Version");

        StringColumn cqVersionsColumn = StringColumn.create("Camel Quarkus version");
        StringColumn durationsColumn = StringColumn.create("Duration");
        StringColumn jvmMeasuresColumn = StringColumn.create("JVM req/s [%increase]");
        StringColumn nativeMeasuresColumn = StringColumn.create("Native req/s [%increase]");
        StringColumn statusColumn = StringColumn.create("Status");
        double previousJvmMeasure = Double.POSITIVE_INFINITY;
        double previousNativeMeasure = Double.POSITIVE_INFINITY;

        for (Map.Entry<ComparableVersion, Map<String, Double>> measurePerVersion : measuresPerVersion.entrySet()) {
            cqVersionsColumn.append(measurePerVersion.getKey().toString());
            durationsColumn.append(duration);
            boolean regressionDetected = false;

            double jvmMeasure = measurePerVersion.getValue().get("JVM");
            double percentIncreaseJvm = (previousJvmMeasure == Double.POSITIVE_INFINITY) ? 0.0
                    : ((jvmMeasure / previousJvmMeasure) - 1.0) * 100.0;
            jvmMeasuresColumn.append(String.format(Locale.US, "%.2f req/s [%+.2f%%]", jvmMeasure, percentIncreaseJvm));
            previousJvmMeasure = jvmMeasure;
            if (percentIncreaseJvm <= -5.00) {
                regressionDetected = true;
            }

            if (measurePerVersion.getValue().containsKey("Native")) {
                double nativeMeasure = measurePerVersion.getValue().get("Native");
                double percentIncreaseNative = (previousNativeMeasure == Double.POSITIVE_INFINITY) ? 0.0
                        : ((nativeMeasure / previousNativeMeasure) - 1.0) * 100.0;
                nativeMeasuresColumn
                        .append(String.format(Locale.US, "%.2f req/s [%+.2f%%]", nativeMeasure, percentIncreaseNative));
                previousNativeMeasure = nativeMeasure;
                if (percentIncreaseNative <= -5.00) {
                    regressionDetected = true;
                }
            }

            statusColumn.append(regressionDetected ? "Potential performance regression" : "OK");
        }

        if (!nativeMeasuresColumn.isEmpty()) {
            table.addColumns(cqVersionsColumn, durationsColumn, jvmMeasuresColumn, nativeMeasuresColumn, statusColumn);
        } else {
            table.addColumns(cqVersionsColumn, durationsColumn, jvmMeasuresColumn, statusColumn);
        }

        return table.printAll();
    }

}
