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

#include "chrome/browser/ash/policy/skyvault/histogram_helper.h"

#include <string>

#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
#include "chrome/browser/ash/policy/skyvault/local_files_migration_constants.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"

namespace policy::local_user_files {
namespace {

constexpr char kSkyVaultUMAPrefix[] = "Enterprise.SkyVault.";

// Suffixes for upload flow histograms.
constexpr char kDeleteErrorSuffix[] = "DeleteError";
constexpr char kOneDriveSignInErrorSuffix[] = "SignInError";

// Suffixes for local storage histograms.
constexpr char kLocalStorageEnabledSuffix[] = "LocalStorage.Enabled";
constexpr char kLocalStorageMisconfiguredSuffix[] =
    "LocalStorage.Misconfigured";

// Suffixes for migration flow histograms.
constexpr char kMigrationEnabledSuffix[] = "Enabled";
constexpr char kMigrationMisconfiguredSuffix[] = "Misconfigured";
constexpr char kMigrationResetSuffix[] = "Reset";
constexpr char kMigrationRetrySuffix[] = "Retry";
constexpr char kMigrationStoppedSuffix[] = "Stopped";
constexpr char kMigrationStateErrorContextSuffix[] = "StateErrorContext";
constexpr char kMigrationWrongStateSuffix[] = "WrongState";
constexpr char kMigrationFailedSuffix[] = "Failed";
constexpr char kMigrationSuccessDurationSuffix[] = "SuccessDuration";
constexpr char kMigrationFailureDurationSuffix[] = "FailureDuration";
constexpr char kMigrationWriteAccessErrorSuffix[] = "WriteAccessError";
constexpr char kMigrationUploadErrorSuffix[] = "UploadError";
constexpr char kMigrationWaitForConnectionSuffix[] = "WaitForConnection";
constexpr char kMigrationReconnectionDurationSuffix[] = "ReconnectionDuration";
constexpr char kMigrationCleanupErrorSuffix[] = "CleanupError";
constexpr char kMigrationDialogActionSuffix[] = "DialogAction";
constexpr char kMigrationDialogShownSuffix[] = "DialogShown";
constexpr char kScheduledTimeInPastInformUser[] =
    "ScheduledTimeInPast.InformUser";
constexpr char kScheduledTimeInPastScheduleMigration[] =
    "ScheduledTimeInPast.ScheduleMigration";

// Constants for cloud providers used in histogram names.
constexpr char kGoogleDriveProvider[] = "GoogleDrive";
constexpr char kOneDriveProvider[] = "OneDrive";
constexpr char kDelete[] = "Delete";

// Constants for upload triggers used in histogram names.
constexpr char kDownloadTrigger[] = "Download";
constexpr char kScreenCaptureTrigger[] = "ScreenCapture";
constexpr char kMigrationTrigger[] = "Migration";
constexpr char kCameraTrigger[] = "Camera";

// Min, max, and bucket count for migration duration histograms.
constexpr base::TimeDelta kMigrationDurationMin = base::Milliseconds(1);
constexpr base::TimeDelta kMigrationDurationMax = base::Hours(36);
// Number of buckets calculated to have a bucket size of 5 minutes:
// (kMax in h * 60 min/h) / 5 min/bucket = 36 * 60 / 5 = 432 buckets
constexpr int kMigrationDurationBuckets = 432;

// Min, max, and bucket count for reconnectivity waiting time histograms.
constexpr base::TimeDelta kReconnectionDurationMin = base::Milliseconds(1);
constexpr base::TimeDelta kReconnectionDurationMax = base::Hours(4);
// Number of buckets calculated to have a bucket size of 1 minute:
// (kMax in h * 60 min/h) / 1 min/bucket = 4 * 60 = 240 buckets
constexpr int kReconnectionDurationBuckets = 240;

// Converts `destination` to a string representation used to form a metric name.
std::string GetUMAMigrationDestination(MigrationDestination destination) {
  switch (destination) {
    case MigrationDestination::kNotSpecified:
      NOTREACHED();
    case MigrationDestination::kGoogleDrive:
      return kGoogleDriveProvider;
    case MigrationDestination::kOneDrive:
      return kOneDriveProvider;
    case MigrationDestination::kDelete:
      return kDelete;
  }
}

// Converts `trigger` to a string representation used to form a metric name.
std::string GetUMAAction(UploadTrigger trigger) {
  std::string action;
  switch (trigger) {
    case UploadTrigger::kDownload:
      return kDownloadTrigger;
    case UploadTrigger::kScreenCapture:
      return kScreenCaptureTrigger;
    case UploadTrigger::kMigration:
      return kMigrationTrigger;
    case UploadTrigger::kCamera:
      return kCameraTrigger;
  }
}

std::string GetHistogramName(
    const std::string& suffix,
    std::optional<UploadTrigger> trigger = std::nullopt,
    std::optional<MigrationDestination> destination = std::nullopt) {
  std::vector<std::string> parts = {kSkyVaultUMAPrefix};
  if (trigger.has_value()) {
    parts.push_back(GetUMAAction(trigger.value()));
    parts.push_back(".");
  }
  if (destination.has_value()) {
    parts.push_back(GetUMAMigrationDestination(destination.value()));
    parts.push_back(".");
  }
  parts.push_back(suffix);
  return base::StrCat(parts);
}

}  // namespace

void SkyVaultDeleteErrorHistogram(UploadTrigger trigger,
                                  MigrationDestination destination,
                                  bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kDeleteErrorSuffix, trigger, destination), value);
}

void SkyVaultOneDriveSignInErrorHistogram(UploadTrigger trigger, bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kOneDriveSignInErrorSuffix, trigger,
                       MigrationDestination::kOneDrive),
      value);
}

void SkyVaultLocalStorageEnabledHistogram(bool value) {
  base::UmaHistogramBoolean(GetHistogramName(kLocalStorageEnabledSuffix),
                            value);
}

void SkyVaultLocalStorageMisconfiguredHistogram(bool value) {
  base::UmaHistogramBoolean(GetHistogramName(kLocalStorageMisconfiguredSuffix),
                            value);
}

void SkyVaultMigrationEnabledHistogram(MigrationDestination destination,
                                       bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationEnabledSuffix, UploadTrigger::kMigration,
                       destination),
      value);
}

void SkyVaultMigrationMisconfiguredHistogram(MigrationDestination destination,
                                             bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationMisconfiguredSuffix, UploadTrigger::kMigration,
                       destination),
      value);
}

void SkyVaultMigrationResetHistogram(bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationResetSuffix, UploadTrigger::kMigration),
      value);
}

void SkyVaultMigrationRetryHistogram(int count) {
  base::UmaHistogramCustomCounts(
      GetHistogramName(kMigrationRetrySuffix, UploadTrigger::kMigration), count,
      1, kMaxRetryCount, kMaxRetryCount);
}

void SkyVaultDeletionRetryHistogram(int count) {
  base::UmaHistogramCustomCounts(
      GetHistogramName(kMigrationRetrySuffix, UploadTrigger::kMigration,
                       MigrationDestination::kDelete),
      count, 1, kMaxRetryCount, kMaxRetryCount);
}

void SkyVaultMigrationStoppedHistogram(MigrationDestination destination,
                                       bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationStoppedSuffix, UploadTrigger::kMigration,
                       destination),
      value);
}

void SkyVaultMigrationWrongStateHistogram(MigrationDestination destination,
                                          StateErrorContext context,
                                          State state) {
  base::UmaHistogramEnumeration(
      GetHistogramName(kMigrationStateErrorContextSuffix,
                       UploadTrigger::kMigration, destination),
      context);
  base::UmaHistogramEnumeration(
      GetHistogramName(kMigrationWrongStateSuffix, UploadTrigger::kMigration,
                       destination),
      state);
}

void SkyVaultDeletionDoneHistogram(bool success) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationFailedSuffix, UploadTrigger::kMigration,
                       MigrationDestination::kDelete),
      !success);
}

void SkyVaultMigrationDoneHistograms(MigrationDestination destination,
                                     bool success,
                                     base::TimeDelta duration) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationFailedSuffix, UploadTrigger::kMigration,
                       destination),
      !success);

  const std::string suffix = success ? kMigrationSuccessDurationSuffix
                                     : kMigrationFailureDurationSuffix;
  base::UmaHistogramCustomTimes(
      GetHistogramName(suffix, UploadTrigger::kMigration, destination),
      duration, kMigrationDurationMin, kMigrationDurationMax,
      kMigrationDurationBuckets);
}

void SkyVaultMigrationWriteAccessErrorHistogram(bool value) {
  base::UmaHistogramBoolean(GetHistogramName(kMigrationWriteAccessErrorSuffix,
                                             UploadTrigger::kMigration),
                            value);
}

void SkyVaultMigrationUploadErrorHistogram(MigrationDestination destination,
                                           MigrationUploadError error) {
  base::UmaHistogramEnumeration(
      GetHistogramName(kMigrationUploadErrorSuffix, UploadTrigger::kMigration,
                       destination),
      error);
}

void SkyVaultMigrationWaitForConnectionHistogram(
    MigrationDestination destination,
    bool waiting_for_connection) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationWaitForConnectionSuffix,
                       UploadTrigger::kMigration, destination),
      waiting_for_connection);
}

void SkyVaultMigrationReconnectionDurationHistogram(
    MigrationDestination destination,
    base::TimeDelta duration) {
  base::UmaHistogramCustomTimes(
      GetHistogramName(kMigrationReconnectionDurationSuffix,
                       UploadTrigger::kMigration, destination),
      duration, kReconnectionDurationMin, kReconnectionDurationMax,
      kReconnectionDurationBuckets);
}

void SkyVaultMigrationCleanupErrorHistogram(MigrationDestination destination,
                                            bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationCleanupErrorSuffix, UploadTrigger::kMigration,
                       destination),
      value);
}

void SkyVaultMigrationScheduledTimeInPastInformUser(
    MigrationDestination destination,
    bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kScheduledTimeInPastInformUser,
                       UploadTrigger::kMigration, destination),
      value);
}

void SkyVaultMigrationScheduledTimeInPastScheduleMigration(
    MigrationDestination destination,
    bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kScheduledTimeInPastScheduleMigration,
                       UploadTrigger::kMigration, destination),
      value);
}

void SkyVaultMigrationDialogActionHistogram(MigrationDestination destination,
                                            DialogAction action) {
  base::UmaHistogramEnumeration(
      GetHistogramName(kMigrationDialogActionSuffix, UploadTrigger::kMigration,
                       destination),
      action);
}

void SkyVaultMigrationDialogShownHistogram(MigrationDestination destination,
                                           bool value) {
  base::UmaHistogramBoolean(
      GetHistogramName(kMigrationDialogShownSuffix, UploadTrigger::kMigration,
                       destination),
      value);
}

}  // namespace policy::local_user_files
