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

#include <vector>

#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/url_loader_interceptor.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "url/gurl.h"

namespace content {

namespace {
constexpr char kBaseDataDir[] = "content/test/data/";

constexpr char kAddFencedFrameScript[] = R"(
  const fenced_frame = document.createElement('fencedframe');
  document.body.appendChild(fenced_frame);
)";

}  // namespace

class PrivacySandboxAdsAPIsBrowserTestBase : public ContentBrowserTest {
 public:
  PrivacySandboxAdsAPIsBrowserTestBase() = default;

  void SetUpOnMainThread() override {
    ContentBrowserTest::SetUpOnMainThread();

    // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
    // the origin trial token in the response is associated with a fixed
    // origin, whereas EmbeddedTestServer serves content on a random port.
    url_loader_interceptor_ =
        std::make_unique<URLLoaderInterceptor>(base::BindLambdaForTesting(
            [&](URLLoaderInterceptor::RequestParams* params) -> bool {
              URLLoaderInterceptor::WriteResponse(
                  base::StrCat({kBaseDataDir, params->url_request.url.path()}),
                  params->client.get());

              return true;
            }));

  }

  void TearDownOnMainThread() override {
    url_loader_interceptor_.reset();
  }

  WebContents* web_contents() { return shell()->web_contents(); }

  FrameTreeNode* root() {
    return static_cast<WebContentsImpl*>(web_contents())
        ->GetPrimaryFrameTree()
        .root();
  }

 private:
  std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
};

class PrivacySandboxAdsAPIsM1OverrideBrowserTest
    : public PrivacySandboxAdsAPIsBrowserTestBase {
 public:
  PrivacySandboxAdsAPIsM1OverrideBrowserTest() {
    feature_list_.InitWithFeatures(
        {features::kPrivacySandboxAdsAPIsM1Override,
         network::features::kBrowsingTopics, blink::features::kFledge,
         blink::features::kAdInterestGroupAPI, blink::features::kFencedFrames},
        /*disabled_features=*/{});
  }

 private:
  base::test::ScopedFeatureList feature_list_;
};

IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsM1OverrideBrowserTest,
                       NoOT_FeatureDetected) {
  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.test/title1.html")));

  EXPECT_EQ(true, EvalJs(shell(),
                         "document.featurePolicy.features().includes('"
                         "browsing-topics')"));

  EXPECT_EQ(true, EvalJs(shell(), "document.browsingTopics !== undefined"));
  EXPECT_EQ(true, EvalJs(shell(), "navigator.runAdAuction !== undefined"));
  EXPECT_EQ(true,
            EvalJs(shell(), "navigator.joinAdInterestGroup !== undefined"));

  EXPECT_TRUE(ExecJs(root(), kAddFencedFrameScript));
  EXPECT_EQ(1U, root()->child_count());
}

class PrivacySandboxAdsAPIsM1OverrideNoFeatureBrowserTest
    : public PrivacySandboxAdsAPIsBrowserTestBase {
 public:
  PrivacySandboxAdsAPIsM1OverrideNoFeatureBrowserTest() {
    feature_list_.InitWithFeatures(
        {features::kPrivacySandboxAdsAPIsM1Override},
        {network::features::kBrowsingTopics,
         blink::features::kAdInterestGroupAPI, blink::features::kFledge,
         blink::features::kFencedFrames});
  }

 private:
  base::test::ScopedFeatureList feature_list_;
};

IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsM1OverrideNoFeatureBrowserTest,
                       OverrideWithoutFeature_IDLNotExposed) {
  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.test/title1.html")));

  EXPECT_EQ(false, EvalJs(shell(),
                          "document.featurePolicy.features().includes('"
                          "browsing-topics')"));
  EXPECT_TRUE(ExecJs(root(), kAddFencedFrameScript));
  EXPECT_EQ(0U, root()->child_count());
}

}  // namespace content
