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

#ifndef COMPONENTS_USER_EDUCATION_COMMON_USER_EDUCATION_DATA_H_
#define COMPONENTS_USER_EDUCATION_COMMON_USER_EDUCATION_DATA_H_

#include <map>
#include <ostream>
#include <set>
#include <string>

#include "base/time/time.h"

namespace user_education {

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// Represents the reason that a promo was ended/promo bubble was closed.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.user_education
// GENERATED_JAVA_PREFIX_TO_STRIP: k
enum class FeaturePromoClosedReason {
  // Actions within the FeaturePromo.
  kDismiss = 0,  // Promo dismissed by user.
  kSnooze = 1,   // Promo snoozed by user.
  kAction = 2,   // Custom action taken by user.
  kCancel = 3,   // Promo was cancelled.

  // Actions outside the FeaturePromo.
  kTimeout = 4,         // Promo timed out.
  kAbortPromo = 5,      // Promo aborted by indirect user action.
  kFeatureEngaged = 6,  // Promo closed by indirect user engagement.

  // Controller system actions.
  kOverrideForUIRegionConflict = 7,  // Promo aborted to avoid overlap.
  kOverrideForDemo = 8,              // Promo aborted by the demo system.
  kOverrideForTesting = 9,           // Promo aborted for tests.
  kOverrideForPrecedence = 10,       // Promo aborted for higher priority Promo.

  // Additional ways a promo can be aborted.
  kAbortedByFeature = 11,          // EndPromo() explicitly called.
  kAbortedByAnchorHidden = 12,     // Anchor element disappeared.
  kAbortedByBubbleDestroyed = 13,  // HelpBubble object destroyed.

  kMaxValue = kAbortedByBubbleDestroyed,
};

std::ostream& operator<<(std::ostream& oss,
                         FeaturePromoClosedReason close_reason);

// Per-key dismissal information.
struct KeyedFeaturePromoData {
  KeyedFeaturePromoData() = default;
  KeyedFeaturePromoData(const KeyedFeaturePromoData&) = default;
  KeyedFeaturePromoData(KeyedFeaturePromoData&&) noexcept = default;
  KeyedFeaturePromoData& operator=(const KeyedFeaturePromoData&) = default;
  KeyedFeaturePromoData& operator=(KeyedFeaturePromoData&&) noexcept = default;
  ~KeyedFeaturePromoData() = default;

  bool operator<=>(const KeyedFeaturePromoData& other) const = default;

  int show_count = 0;
  base::Time last_shown_time;
};

using KeyedFeaturePromoDataMap = std::map<std::string, KeyedFeaturePromoData>;

// Dismissal and snooze information.
struct FeaturePromoData {
  FeaturePromoData();
  FeaturePromoData(const FeaturePromoData&);
  FeaturePromoData(FeaturePromoData&&) noexcept;
  FeaturePromoData& operator=(const FeaturePromoData&);
  FeaturePromoData& operator=(FeaturePromoData&&) noexcept;
  ~FeaturePromoData();

  bool is_dismissed = false;
  FeaturePromoClosedReason last_dismissed_by =
      FeaturePromoClosedReason::kCancel;
  base::Time first_show_time;
  base::Time last_show_time;
  base::Time last_snooze_time;
  int snooze_count = 0;
  int show_count = 0;
  int promo_index = 0;
  KeyedFeaturePromoDataMap shown_for_keys;
};

// Data about the current session, which can persist across browser restarts.
struct UserEducationSessionData {
  UserEducationSessionData();
  UserEducationSessionData(const UserEducationSessionData&);
  UserEducationSessionData(UserEducationSessionData&&) noexcept;
  UserEducationSessionData& operator=(const UserEducationSessionData&);
  UserEducationSessionData& operator=(UserEducationSessionData&&) noexcept;
  ~UserEducationSessionData();

  // The beginning of the most recent session.
  base::Time start_time;

  // The last known time the browser was active.
  base::Time most_recent_active_time;

  // The (potentially non-monotonic but generally increasing) session number.
  // Any code which relies on this number should respond to an out-of-order
  // value as a cue to reset anything session-count-related, as it likely means
  // the user has reset session data from the User Education internals page.
  //
  // Note that zero is a null/invalid value and should never be returned from a
  // data read.
  int session_number = 1;
};

// Data that must be kept across browser restart to support the feature promo
// policy.
struct FeaturePromoPolicyData {
  FeaturePromoPolicyData();
  FeaturePromoPolicyData(const FeaturePromoPolicyData&);
  FeaturePromoPolicyData(FeaturePromoPolicyData&&) noexcept;
  FeaturePromoPolicyData& operator=(const FeaturePromoPolicyData&);
  FeaturePromoPolicyData& operator=(FeaturePromoPolicyData&&) noexcept;
  ~FeaturePromoPolicyData();

  // The time of the last heavyweight promotion the user saw
  base::Time last_heavyweight_promo_time;
};

// Data about the "New" Badge for a particular feature.
struct NewBadgeData {
  // The number of times the "New" Badge has been shown.
  int show_count = 0;

  // The number of times the promoted entry point has been used.
  int used_count = 0;

  // The first time the promoted feature is enabled.
  base::Time feature_enabled_time;
};

// Data used by the ProductMessagingController.
struct ProductMessagingData {
  ProductMessagingData();
  ProductMessagingData(const ProductMessagingData&);
  ProductMessagingData(ProductMessagingData&&) noexcept;
  ProductMessagingData& operator=(const ProductMessagingData&);
  ProductMessagingData& operator=(ProductMessagingData&&) noexcept;
  ~ProductMessagingData();

  // Notices that were shown this session.
  std::set<std::string> shown_notices;
};

// Data pertaining to a single NTP promo.
struct NtpPromoData {
  NtpPromoData();
  NtpPromoData(const NtpPromoData&);
  NtpPromoData(NtpPromoData&&) noexcept;
  NtpPromoData& operator=(const NtpPromoData&);
  NtpPromoData& operator=(NtpPromoData&&) noexcept;
  ~NtpPromoData();

  bool operator<=>(const NtpPromoData& other) const = default;

  // Time at which the promo was most recently clicked.
  base::Time last_clicked;

  // Time at which the promo was first seen to be complete.
  base::Time completed;

  // The session in which this promo was last shown in the top spot.
  int last_session = 0;

  // The number of session this promo has been shown in the top spot, since
  // it most recently claimed the top spot. When reclaiming top spot,
  // this value must be reset.
  int session_count_in_term = 0;

  // The number of times this promo has started a run of sessions in the top
  // spot.
  int term_count = 0;

  // Timestamp of when the promo started a run of sessions in the top spot.
  base::Time term_start_time;

  // Time at which the promo was dismissed by the user.
  base::Time dismissed_time;
};

using KeyedNtpPromoDataMap = std::map<std::string, NtpPromoData>;

// Data pertaining to the NTP promo system as a whole.
struct NtpPromoPreferences {
  NtpPromoPreferences();
  NtpPromoPreferences(const NtpPromoPreferences&);
  NtpPromoPreferences(NtpPromoPreferences&&) noexcept;
  NtpPromoPreferences& operator=(const NtpPromoPreferences&);
  NtpPromoPreferences& operator=(NtpPromoPreferences&&) noexcept;
  ~NtpPromoPreferences();

  bool operator<=>(const NtpPromoPreferences& other) const = default;

  // Whether all promos are disabled.
  bool disabled = false;
};

}  // namespace user_education

#endif  // COMPONENTS_USER_EDUCATION_COMMON_USER_EDUCATION_DATA_H_
