// 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.

#include "chrome/browser/supervised_user/chromeos/supervised_user_web_content_handler_impl.h"

#include <memory>
#include <string>

#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/supervised_user/chromeos/mock_large_icon_service.h"
#include "chrome/browser/supervised_user/chromeos/supervised_user_favicon_request_handler.h"
#include "chrome/test/base/testing_profile.h"
#include "components/supervised_user/core/browser/family_link_settings_service.h"
#include "components/supervised_user/core/common/supervised_user_constants.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace {
class MockFamilyLinkSettingsService
    : public supervised_user::FamilyLinkSettingsService {
 public:
  MOCK_METHOD1(RecordLocalWebsiteApproval, void(const std::string& host));
};
}  // namespace

// TODO(b/273692421): Extend unit test scope of all the methods in
// SupervisedUserWebContentHandlerImpl.

class SupervisedUserWebContentHandlerImplTest : public ::testing::Test {
 public:
  SupervisedUserWebContentHandlerImplTest() {
    TestingProfile::Builder builder;
    profile_ = IdentityTestEnvironmentProfileAdaptor::
        CreateProfileForIdentityTestEnvironment(builder);
  }

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

  ~SupervisedUserWebContentHandlerImplTest() override = default;

  content::BrowserTaskEnvironment& task_environment() {
    return task_environment_;
  }

  MockLargeIconService& large_icon_service() { return large_icon_service_; }
  TestingProfile* GetProfilePtr() { return profile_.get(); }

 private:
  content::BrowserTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  std::unique_ptr<TestingProfile> profile_;
  MockLargeIconService large_icon_service_;
};

TEST_F(SupervisedUserWebContentHandlerImplTest,
       LocalWebApprovalApprovedChromeOSTest) {
  base::HistogramTester histogram_tester;
  const GURL url("http://www.example.com");

  testing::NiceMock<MockFamilyLinkSettingsService>
      FamilyLinkSettingsServiceMock;
  EXPECT_CALL(FamilyLinkSettingsServiceMock,
              RecordLocalWebsiteApproval(url.GetHost()));

  auto result = std::make_unique<ash::ParentAccessDialog::Result>();
  result->status = ash::ParentAccessDialog::Result::Status::kApproved;
  result->parent_access_token = "TEST_TOKEN";
  result->parent_access_token_expire_timestamp =
      base::Time::FromSecondsSinceUnixEpoch(123456L);

  // Capture approval start time and forward clock by the fake approval
  // duration.
  const base::TimeTicks start_time = base::TimeTicks::Now();
  const base::TimeDelta approval_duration = base::Seconds(35);
  task_environment().FastForwardBy(approval_duration);

  std::unique_ptr<content::WebContents> web_contents =
      content::WebContents::Create(
          content::WebContents::CreateParams(GetProfilePtr()));
  SupervisedUserWebContentHandlerImpl web_content_handler(
      web_contents.get(), url, large_icon_service(), content::FrameTreeNodeId(),
      /*interstitial_navigation_id=*/0);

  web_content_handler.OnLocalApprovalRequestCompleted(
      FamilyLinkSettingsServiceMock, url, start_time, std::move(result));

  histogram_tester.ExpectUniqueSample(
      supervised_user::WebContentHandler::GetLocalApprovalResultHistogram(),
      supervised_user::LocalApprovalResult::kApproved, 1);
  histogram_tester.ExpectTotalCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      1);
  histogram_tester.ExpectTimeBucketCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      approval_duration, 1);
}

TEST_F(SupervisedUserWebContentHandlerImplTest,
       LocalWebApprovalDeclinedChromeOSTest) {
  base::HistogramTester histogram_tester;
  const GURL url("http://www.example.com");

  testing::NiceMock<MockFamilyLinkSettingsService>
      FamilyLinkSettingsServiceMock;
  EXPECT_CALL(FamilyLinkSettingsServiceMock,
              RecordLocalWebsiteApproval(url.GetHost()))
      .Times(0);

  auto result = std::make_unique<ash::ParentAccessDialog::Result>();
  result->status = ash::ParentAccessDialog::Result::Status::kDeclined;

  // Capture approval start time and forward clock by the fake approval
  // duration.
  const base::TimeTicks start_time = base::TimeTicks::Now();
  const base::TimeDelta approval_duration = base::Seconds(35);
  task_environment().FastForwardBy(approval_duration);

  std::unique_ptr<content::WebContents> web_contents =
      content::WebContents::Create(
          content::WebContents::CreateParams(GetProfilePtr()));
  SupervisedUserWebContentHandlerImpl web_content_handler(
      web_contents.get(), url, large_icon_service(), content::FrameTreeNodeId(),
      /*interstitial_navigation_id=*/0);

  web_content_handler.OnLocalApprovalRequestCompleted(
      FamilyLinkSettingsServiceMock, url, start_time, std::move(result));

  histogram_tester.ExpectUniqueSample(
      supervised_user::WebContentHandler::GetLocalApprovalResultHistogram(),
      supervised_user::LocalApprovalResult::kDeclined, 1);
  histogram_tester.ExpectTotalCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      1);
  histogram_tester.ExpectTimeBucketCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      approval_duration, 1);
}

TEST_F(SupervisedUserWebContentHandlerImplTest,
       LocalWebApprovalCanceledChromeOSTest) {
  base::HistogramTester histogram_tester;
  const GURL url("http://www.example.com");

  testing::NiceMock<MockFamilyLinkSettingsService>
      FamilyLinkSettingsServiceMock;
  EXPECT_CALL(FamilyLinkSettingsServiceMock,
              RecordLocalWebsiteApproval(url.GetHost()))
      .Times(0);

  auto result = std::make_unique<ash::ParentAccessDialog::Result>();
  result->status = ash::ParentAccessDialog::Result::Status::kCanceled;

  // Capture approval start time and forward clock by the fake approval
  // duration.
  const base::TimeTicks start_time = base::TimeTicks::Now();
  const base::TimeDelta approval_duration = base::Seconds(35);
  task_environment().FastForwardBy(approval_duration);

  std::unique_ptr<content::WebContents> web_contents =
      content::WebContents::Create(
          content::WebContents::CreateParams(GetProfilePtr()));
  SupervisedUserWebContentHandlerImpl web_content_handler(
      web_contents.get(), url, large_icon_service(), content::FrameTreeNodeId(),
      /*interstitial_navigation_id=*/0);

  web_content_handler.OnLocalApprovalRequestCompleted(
      FamilyLinkSettingsServiceMock, url, start_time, std::move(result));

  // Check that the approval duration was NOT recorded for canceled request.
  histogram_tester.ExpectTotalCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      0);
  histogram_tester.ExpectUniqueSample(
      supervised_user::WebContentHandler::GetLocalApprovalResultHistogram(),
      supervised_user::LocalApprovalResult::kCanceled, 1);
}

TEST_F(SupervisedUserWebContentHandlerImplTest,
       LocalWebApprovalErrorChromeOSTest) {
  base::HistogramTester histogram_tester;
  const GURL url("http://www.example.com");

  testing::NiceMock<MockFamilyLinkSettingsService>
      FamilyLinkSettingsServiceMock;
  EXPECT_CALL(FamilyLinkSettingsServiceMock,
              RecordLocalWebsiteApproval(url.GetHost()))
      .Times(0);

  auto result = std::make_unique<ash::ParentAccessDialog::Result>();
  result->status = ash::ParentAccessDialog::Result::Status::kError;

  // Capture approval start time and forward clock by the fake approval
  // duration.
  const base::TimeTicks start_time = base::TimeTicks::Now();
  const base::TimeDelta approval_duration = base::Seconds(35);
  task_environment().FastForwardBy(approval_duration);

  std::unique_ptr<content::WebContents> web_contents =
      content::WebContents::Create(
          content::WebContents::CreateParams(GetProfilePtr()));
  SupervisedUserWebContentHandlerImpl web_content_handler(
      web_contents.get(), url, large_icon_service(), content::FrameTreeNodeId(),
      /*interstitial_navigation_id=*/0);

  web_content_handler.OnLocalApprovalRequestCompleted(
      FamilyLinkSettingsServiceMock, url, start_time, std::move(result));

  // Check that the approval duration was NOT recorded on error.
  histogram_tester.ExpectTotalCount(
      supervised_user::WebContentHandler::
          GetLocalApprovalDurationMillisecondsHistogram(),
      0);
  histogram_tester.ExpectUniqueSample(
      supervised_user::WebContentHandler::GetLocalApprovalResultHistogram(),
      supervised_user::LocalApprovalResult::kError, 1);
}
