// 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 CHROME_BROWSER_SAFE_BROWSING_PHISHY_INTERACTION_TRACKER_H_
#define CHROME_BROWSER_SAFE_BROWSING_PHISHY_INTERACTION_TRACKER_H_

#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "content/public/browser/web_contents.h"

namespace safe_browsing {

class SafeBrowsingUIManager;

struct PhishyPageInteractionDetails {
  PhishyPageInteractionDetails(int occurrence_count,
                               int64_t first_timestamp,
                               int64_t last_timestamp);
  int occurrence_count;
  int64_t first_timestamp;
  int64_t last_timestamp;
};

using PhishySiteInteractionMap =
    std::map<ClientSafeBrowsingReportRequest::PhishySiteInteraction::
                 PhishySiteInteractionType,
             PhishyPageInteractionDetails>;

// PhishyInteractionTracker manages and logs interactions that users have with
// pages they've reached after bypassing the Safe Browsing interstitial.
class PhishyInteractionTracker {
 public:
  explicit PhishyInteractionTracker(content::WebContents* web_contents);

  PhishyInteractionTracker(const PhishyInteractionTracker&) = delete;
  PhishyInteractionTracker& operator=(const PhishyInteractionTracker&) = delete;

  ~PhishyInteractionTracker();

  // Records unlogged data if the page is phishy when the WebContents is about
  // to be destroyed.
  void WebContentsDestroyed();

  // Records unlogged data if the page is phishy. Gets called when the primary
  // page is changed.
  void HandlePageChanged();

  // Tracks phishy paste events.
  void HandlePasteEvent();

  // Tracks typing and click events.
  void HandleInputEvent(const blink::WebInputEvent& event);

  // Set the inactivity_delay_ so we can test logged phishy events.
  void SetInactivityDelayForTesting(base::TimeDelta inactivity_delay);

  // Set the UI manager so we can test logged phishy events.
  void SetUIManagerForTesting(
      safe_browsing::SafeBrowsingUIManager* ui_manager_for_testing) {
    ui_manager_for_testing_ = ui_manager_for_testing;
  }

 private:
  // Returns true if the primary page is a phishing page.
  bool IsSitePhishy();

  // Resets values that help track phishy events. Called when the primary page
  // changes.
  void ResetLoggingHelpers();

  // Handles logging for phishy events. Posts a delayed task that logs phishy
  // event data if the user is inactive.
  void HandlePhishyInteraction(
      const ClientSafeBrowsingReportRequest::PhishySiteInteraction::
          PhishySiteInteractionType& interaction);

  // Logs the first event user action. Called on the first occurrence of each
  // type of interaction.
  void RecordFirstInteractionOccurrence(
      ClientSafeBrowsingReportRequest::PhishySiteInteraction::
          PhishySiteInteractionType interaction);

  // Returns true if the user has been inactive on the page for at least
  // inactivity_delay_.
  bool IsUserInactive() {
    return base::Time::Now() - last_interaction_ts_ >= inactivity_delay_;
  }

  // If the user is inactive and the data is unlogged, log the phishy
  // interaction data.
  void MaybeLogIfUserInactive();

  // Helper for logging UMA data.
  void LogPageData();

  // Tracks the WebContents for the current page.
  raw_ptr<content::WebContents> web_contents_ = nullptr;

  // Records the number of occurrences of different user interactions with a
  // phishy page and first/last timestamps of the interaction occurrences. Used
  // for recording metrics.
  PhishySiteInteractionMap phishy_page_interaction_data_;

  // Tracks the latest phishy page interaction occurrence so that we can log
  // metrics after some period of inactivity.
  base::Time last_interaction_ts_;

  // Period of inactivity with a phishy page before we log user interaction
  // metrics.
  base::TimeDelta inactivity_delay_;

  // Used to call a method if the user is inactive for a period of time.
  base::OneShotTimer inactivity_timer_;

  // Tracks the URL so that if metric recording is necessary, we have access to
  // the phishy URL after the page changes.
  GURL current_url_;

  // Tracks the page URL for metric recording.
  GURL current_page_url_;

  // Returns true if the data for the current site has been logged already.
  bool is_data_logged_ = false;

  // Returns true if the current page is phishy.
  bool is_phishy_ = false;

  // UI Manager that returns specific threat types for testing.
  raw_ptr<safe_browsing::SafeBrowsingUIManager, DanglingUntriaged>
      ui_manager_for_testing_ = nullptr;
};

}  // namespace safe_browsing

#endif  // CHROME_BROWSER_SAFE_BROWSING_PHISHY_INTERACTION_TRACKER_H_
