package com.atlassian.bitbucket.installer;

import com.atlassian.bitbucket.installer.analytics.PingbackClient;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.install4j.api.Util;
import com.install4j.api.context.InstallerContext;

import java.util.Map;

public class Tracker {

    private final PingbackClient pingbackClient;

    public Tracker(PingbackClient pingbackClient) {
        this.pingbackClient = pingbackClient;
    }

    /**
     * Track an event asynchronously. This method is fire-and-forget, and the response from the
     * pingback server is effectively ignored. This is the safe way of doing it so that the installer
     * flow is not interrupted.
     *
     * @param context the {@link com.install4j.api.context.InstallerContext} for this request
     * @param event the event name to be tracked
     * @return always returns {@code true} to allow for one-liners in Install4J contexts that require a boolean response
     */
    public boolean track(InstallerContext context, final String event) {
        InstallationDetails details = (InstallationDetails) context.getVariable("installation.details");
        final String os = Platform.current().toString() + (context.isConsole() ? "-CONSOLE" : "");
        final String version = (String) context.getVariable("sys.version");
        final String installationId = details.getInstallationId();
        Thread thread = new Thread(() -> {
            trackSynchronously(event, os, version, installationId);
        });
        thread.setDaemon(true);
        thread.start();
        return true;
    }

    /**
     * Track an event synchronously - this method will wait until the pingback has completed (or failed)
     * before returning.  You probably want to use {@link #track(com.install4j.api.context.InstallerContext, String)} to
     * send the pingback asynchronously and get data from the context.
     *
     * @param event the event name to be tracked
     * @param os a string representing the operating system the installer is running on
     * @param version the product version being installed
     * @param installationId a unique identifier for this installation
     * @return always returns {@code true} to allow for one-liners in Install4J contexts that require a boolean response
     */
    @VisibleForTesting
    boolean trackSynchronously(String event, String os, String version, String installationId) {
        try {
            Map<String, String> additionalParams = ImmutableMap.of("os", os);
            Util.logInfo(null, String.format("Sending pingback for event %s", event));
            int statusCode = pingbackClient.pingback("stash",
                    version,
                    installationId,
                    event,
                    additionalParams);
            Util.logInfo(null, String.format("Pingback for %s succeeded with return code %d", event, statusCode));
        } catch (Exception ex) {
            Util.logError(null, String.format("Failed to send pingback: %s", ex.getLocalizedMessage()));
            Util.log(ex);
        }
        return true;
    }
}
