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

#include "components/safe_browsing/content/browser/download/download_stats.h"

#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/time/time.h"
#include "components/download/public/common/download_content.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/safe_browsing/content/common/file_type_policies.h"

namespace {

using safe_browsing::FileTypePolicies;

constexpr char kShownMetricSuffix[] = ".Shown";
constexpr char kBypassedMetricSuffix[] = ".Bypassed";

std::string GetDangerTypeMetricSuffix(
    download::DownloadDangerType danger_type) {
  switch (danger_type) {
    case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
      return ".DangerousFileType";
    case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
      return ".Safe";
    case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
    case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
    case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
    case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE:
    case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
    case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS:
      return ".Malicious";
    case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
      return ".Uncommon";
    case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
    case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_LOCAL_PASSWORD_SCANNING:
    case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
    case download::DOWNLOAD_DANGER_TYPE_ASYNC_LOCAL_PASSWORD_SCANNING:
    case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED:
    case download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE:
    case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
    case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK:
    case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE:
    case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_FAILED:
    case download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
    case download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
    case download::DOWNLOAD_DANGER_TYPE_ALLOWLISTED_BY_POLICY:
    case download::DOWNLOAD_DANGER_TYPE_BLOCKED_SCAN_FAILED:
    case download::DOWNLOAD_DANGER_TYPE_MAX:
    case download::DOWNLOAD_DANGER_TYPE_FORCE_SAVE_TO_GDRIVE:
    case download::DOWNLOAD_DANGER_TYPE_FORCE_SAVE_TO_ONEDRIVE:
      return ".Others";
  }
}

void RecordDangerousWarningFileType(const base::FilePath& file_path,
                                    const std::string& metrics_suffix) {
  base::UmaHistogramSparse(
      "SBClientDownload.Warning.FileType" + metrics_suffix,
      FileTypePolicies::GetInstance()->UmaValueForFile(file_path));
}

void RecordDangerousWarningIsHttps(bool is_https,
                                   const std::string& metrics_suffix) {
  base::UmaHistogramBoolean(
      "SBClientDownload.Warning.DownloadIsHttps" + metrics_suffix, is_https);
}

void RecordDangerousWarningHasUserGesture(bool has_user_gesture,
                                          const std::string& metrics_suffix) {
  base::UmaHistogramBoolean(
      "SBClientDownload.Warning.DownloadHasUserGesture" + metrics_suffix,
      has_user_gesture);
}

}  // namespace

namespace safe_browsing {

void RecordDangerousDownloadWarningShown(
    download::DownloadDangerType danger_type,
    const base::FilePath& file_path,
    bool is_https,
    bool has_user_gesture) {
  std::string metrics_suffix =
      GetDangerTypeMetricSuffix(danger_type) + kShownMetricSuffix;
  RecordDangerousWarningFileType(file_path, metrics_suffix);
  RecordDangerousWarningIsHttps(is_https, metrics_suffix);
  RecordDangerousWarningHasUserGesture(has_user_gesture, metrics_suffix);
  base::RecordAction(
      base::UserMetricsAction("SafeBrowsing.Download.WarningShown"));
}

void RecordDangerousDownloadWarningBypassed(
    download::DownloadDangerType danger_type,
    const base::FilePath& file_path,
    bool is_https,
    bool has_user_gesture) {
  std::string metrics_suffix =
      GetDangerTypeMetricSuffix(danger_type) + kBypassedMetricSuffix;
  RecordDangerousWarningFileType(file_path, metrics_suffix);
  RecordDangerousWarningIsHttps(is_https, metrics_suffix);
  RecordDangerousWarningHasUserGesture(has_user_gesture, metrics_suffix);
  base::RecordAction(
      base::UserMetricsAction("SafeBrowsing.Download.WarningBypassed"));
}

void RecordDownloadFileTypeAttributes(
    DownloadFileType::DangerLevel danger_level,
    bool has_user_gesture,
    bool visited_referrer_before,
    std::optional<base::Time> last_bypass_time) {
  if (danger_level != DownloadFileType::ALLOW_ON_USER_GESTURE) {
    return;
  }
  base::UmaHistogramEnumeration(
      "SBClientDownload.UserGestureFileType.Attributes",
      UserGestureFileTypeAttributes::TOTAL_TYPE_CHECKED);
  if (has_user_gesture) {
    base::UmaHistogramEnumeration(
        "SBClientDownload.UserGestureFileType.Attributes",
        UserGestureFileTypeAttributes::HAS_USER_GESTURE);
  }
  if (visited_referrer_before) {
    base::UmaHistogramEnumeration(
        "SBClientDownload.UserGestureFileType.Attributes",
        UserGestureFileTypeAttributes::HAS_REFERRER_VISIT);
  }
  if (has_user_gesture && visited_referrer_before) {
    base::UmaHistogramEnumeration(
        "SBClientDownload.UserGestureFileType.Attributes",
        UserGestureFileTypeAttributes::
            HAS_BOTH_USER_GESTURE_AND_REFERRER_VISIT);
  }
  if (last_bypass_time) {
    base::UmaHistogramEnumeration(
        "SBClientDownload.UserGestureFileType.Attributes",
        UserGestureFileTypeAttributes::HAS_BYPASSED_DOWNLOAD_WARNING);
  }
}

}  // namespace safe_browsing
