// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/security_interstitials/core/metrics_helper.h"

#include <memory>
#include <utility>

#include "base/metrics/histogram.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "components/history/core/browser/history_service.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"

using base::RecordAction;
using base::UserMetricsAction;

namespace security_interstitials {

namespace {

// Directly adds to the UMA histograms, using the same properties as
// UMA_HISTOGRAM_ENUMERATION, because the macro doesn't allow non-constant
// histogram names.
void RecordSingleDecisionToMetrics(MetricsHelper::Decision decision,
                                   const std::string& histogram_name) {
  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
      histogram_name, 1, MetricsHelper::MAX_DECISION,
      MetricsHelper::MAX_DECISION + 1,
      base::HistogramBase::kUmaTargetedHistogramFlag);
  histogram->Add(decision);
}

void RecordSingleInteractionToMetrics(MetricsHelper::Interaction interaction,
                                      const std::string& histogram_name) {
  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
      histogram_name, 1, MetricsHelper::MAX_INTERACTION,
      MetricsHelper::MAX_INTERACTION + 1,
      base::HistogramBase::kUmaTargetedHistogramFlag);
  histogram->Add(interaction);
}

void MaybeRecordDecisionAsAction(MetricsHelper::Decision decision,
                                 const std::string& metric_name) {
  if (decision == MetricsHelper::PROCEED) {
    if (metric_name == "malware")
      RecordAction(UserMetricsAction("MalwareInterstitial.Proceed"));
    else if (metric_name == "harmful")
      RecordAction(UserMetricsAction("HarmfulInterstitial.Proceed"));
    else if (metric_name == "ssl_overridable")
      RecordAction(UserMetricsAction("SSLOverridableInterstitial.Proceed"));
  } else if (decision == MetricsHelper::DONT_PROCEED) {
    if (metric_name == "malware")
      RecordAction(UserMetricsAction("MalwareInterstitial.Back"));
    else if (metric_name == "harmful")
      RecordAction(UserMetricsAction("HarmfulInterstitial.Back"));
    else if (metric_name == "ssl_overridable")
      RecordAction(UserMetricsAction("SSLOverridableInterstitial.Back"));
    else if (metric_name == "ssl_nonoverridable")
      RecordAction(UserMetricsAction("SSLNonOverridableInsterstitial.Back"));
    else if (metric_name == "bad_clock")
      RecordAction(UserMetricsAction("BadClockInterstitial.Back"));
  }
}

void MaybeRecordInteractionAsAction(MetricsHelper::Interaction interaction,
                                    const std::string& metric_name) {
  if (interaction == MetricsHelper::TOTAL_VISITS) {
    if (metric_name == "malware")
      RecordAction(UserMetricsAction("MalwareInterstitial.Show"));
    else if (metric_name == "harmful")
      RecordAction(UserMetricsAction("HarmfulInterstitial.Show"));
    else if (metric_name == "ssl_overridable")
      RecordAction(UserMetricsAction("SSLOverridableInterstitial.Show"));
    else if (metric_name == "ssl_nonoverridable")
      RecordAction(UserMetricsAction("SSLNonOverridableInterstitial.Show"));
    else if (metric_name == "bad_clock")
      RecordAction(UserMetricsAction("BadClockInterstitial.Show"));
  } else if (interaction == MetricsHelper::SHOW_ADVANCED) {
    if (metric_name == "malware") {
      RecordAction(UserMetricsAction("MalwareInterstitial.Advanced"));
    } else if (metric_name == "harmful") {
      RecordAction(UserMetricsAction("HarmfulInterstitial.Advanced"));
    } else if (metric_name == "ssl_overridable" ||
               metric_name == "ssl_nonoverridable") {
      RecordAction(UserMetricsAction("SSLInterstitial.Advanced"));
    }
  } else if (interaction == MetricsHelper::RELOAD) {
    if (metric_name == "ssl_nonoverridable")
      RecordAction(UserMetricsAction("SSLInterstitial.Reload"));
  } else if (interaction == MetricsHelper::OPEN_TIME_SETTINGS) {
    if (metric_name == "bad_clock")
      RecordAction(UserMetricsAction("BadClockInterstitial.Settings"));
  }
}

}  // namespace

MetricsHelper::~MetricsHelper() {}

MetricsHelper::ReportDetails::ReportDetails() {}

MetricsHelper::ReportDetails::ReportDetails(const ReportDetails& other) =
    default;

MetricsHelper::ReportDetails::~ReportDetails() {}

MetricsHelper::MetricsHelper(const GURL& request_url,
                             const ReportDetails settings,
                             history::HistoryService* history_service)
    : request_url_(request_url), settings_(settings), num_visits_(-1) {
  DCHECK(!settings_.metric_prefix.empty());
  if (history_service) {
    history_service->GetVisibleVisitCountToHost(
        request_url_,
        base::Bind(&MetricsHelper::OnGotHistoryCount, base::Unretained(this)),
        &request_tracker_);
  }
}

void MetricsHelper::RecordUserDecision(Decision decision) {
  const std::string histogram_name(
      "interstitial." + settings_.metric_prefix + ".decision");
  RecordUserDecisionToMetrics(decision, histogram_name);
  // Record additional information about sites that users have visited before.
  // Report |decision| and SHOW together, filtered by the same history state
  // so they they are paired regardless of when if num_visits_ is populated.
  if (num_visits_ > 0 && (decision == PROCEED || decision == DONT_PROCEED)) {
    RecordUserDecisionToMetrics(SHOW, histogram_name + ".repeat_visit");
    RecordUserDecisionToMetrics(decision, histogram_name + ".repeat_visit");
  }

  MaybeRecordDecisionAsAction(decision, settings_.metric_prefix);
}

void MetricsHelper::RecordUserDecisionToMetrics(
    Decision decision,
    const std::string& histogram_name) {
  // Record the decision, and additionally |with extra_suffix|.
  RecordSingleDecisionToMetrics(decision, histogram_name);
  if (!settings_.extra_suffix.empty()) {
    RecordSingleDecisionToMetrics(
        decision, histogram_name + "." + settings_.extra_suffix);
  }
}

void MetricsHelper::RecordUserInteraction(Interaction interaction) {
  const std::string histogram_name(
      "interstitial." + settings_.metric_prefix + ".interaction");
  RecordSingleInteractionToMetrics(interaction, histogram_name);
  if (!settings_.extra_suffix.empty()) {
    RecordSingleInteractionToMetrics(
        interaction, histogram_name + "." + settings_.extra_suffix);
  }

  MaybeRecordInteractionAsAction(interaction, settings_.metric_prefix);
}

void MetricsHelper::RecordShutdownMetrics() {
  RecordExtraShutdownMetrics();
}

int MetricsHelper::NumVisits() {
  return num_visits_;
}

void MetricsHelper::RecordExtraUserDecisionMetrics(Decision decision) {}

void MetricsHelper::RecordExtraUserInteractionMetrics(Interaction interaction) {
}

void MetricsHelper::RecordExtraShutdownMetrics() {}

void MetricsHelper::OnGotHistoryCount(bool success,
                                      int num_visits,
                                      base::Time /*first_visit*/) {
  if (success)
    num_visits_ = num_visits;
}

}  // namespace security_interstitials
