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

#include <optional>
#include <string>
#include <string_view>

#include "base/files/file_path.h"
#include "base/logging.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/tab_ui_helper.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "chrome/test/supervised_user/browser_user.h"
#include "chrome/test/supervised_user/family_live_test.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/supervised_user/test_support/family_link_settings_state_management.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/state_observer.h"
#include "url/gurl.h"

namespace supervised_user {
namespace {

// Unblocks rendering the youtube iframe.
constexpr std::string_view kYouTubeHostPattern = "*.youtube.com";
// Unblocks playing back the video
constexpr std::string_view kGoogleVideoHostPattern = "*.googlevideo.com";
// When this string is present in frame's HTML, it indicates that the
// interstitial is shown.
constexpr std::string_view kInterstitialBodyClass =
    "supervised-user-verify-subframe";

// Returns true, when in the given `browser`, in a tab with title `tab_title`,
// there is a iframe with name `iframe_name` that displays the YouTube
// interstitial. Note that the interstitial's presence is validated by looking
// for a specific class in the inner HTML of the iframe rather than parsing the
// DOM structure.
bool IsYouTubeInterstitialDisplayedInIframe(BrowserWindowInterface& browser,
                                            std::u16string_view tab_title,
                                            std::string_view iframe_name) {
  content::WebContents* web_contents = nullptr;
  TabStripModel* const tab_strip_model = browser.GetTabStripModel();
  for (int i = 0; i < tab_strip_model->count(); ++i) {
    tabs::TabInterface* tab = tab_strip_model->GetTabAtIndex(i);
    const std::u16string wc_title = TabUIHelper::From(tab)->GetTitle();
    if (wc_title == tab_title) {
      web_contents = tab->GetContents();
      break;
    }
  }
  CHECK(web_contents) << "Expected tab with supplied title";

  content::RenderFrameHost* rfh = content::FrameMatchingPredicate(
      web_contents->GetPrimaryPage(),
      base::BindRepeating(&content::FrameMatchesName, iframe_name));

  CHECK(rfh) << "Expected iframe with supplied name";
  std::string innerHTML =
      content::EvalJs(rfh, "document.documentElement.innerHTML")
          .ExtractString();
  return innerHTML.find(kInterstitialBodyClass) != std::string::npos;
}

// All tests in this unit are subject to flakiness because they interact with a
// system that can be externally modified during execution.
// TODO(crbug.com/301587955): Fix placement of supervised_user/e2e test files
// and their dependencies.
class KidsProfileUiTest
    : public InteractiveFamilyLiveTest,
      public testing::WithParamInterface<FamilyLiveTest::RpcMode> {
 public:
  KidsProfileUiTest()
      : InteractiveFamilyLiveTest(
            GetParam(),
            /*extra_enabled_hosts=*/{kYouTubeHostPattern,
                                     kGoogleVideoHostPattern}) {}

  void SetUpOnMainThread() override {
    InteractiveFamilyLiveTest::SetUpOnMainThread();
    test_server_.AddDefaultHandlers(
        base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
    CHECK(test_server_.Start());
    LOG(INFO) << "Embedded test server is listening on "
              << test_server_.host_port_pair().ToString() << ".";
  }

 protected:
  net::test_server::EmbeddedTestServer& TestServer() { return test_server_; }

 private:
  // Serves static page that embeds an arbitrary YouTube widget (actual video is
  // irrelevant).
  net::test_server::EmbeddedTestServer test_server_;
};

IN_PROC_BROWSER_TEST_P(KidsProfileUiTest, DisplayInterstitialInPendingState) {
  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kYouTubeTab);
  DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<bool>,
                                      kInterstitialDisplayed);

  SigninToBrowser();
  child().SignOutFromWeb();

  GURL url_with_youtube_iframes =
      TestServer().GetURL("/supervised_user/with_embedded_youtube_videos.html");

  BrowserWindowInterface& child_browser = child().browser();

  RunTestSequence(
      AddInstrumentedTab(kYouTubeTab, url_with_youtube_iframes, std::nullopt,
                         &child().browser()),

      // Refer to with_embedded_youtube_videos.html to get title and iframe
      // names.
      PollState(
          kInterstitialDisplayed,
          [&child_browser]() {
            return IsYouTubeInterstitialDisplayedInIframe(
                child_browser,
                u"Supervised User test: page with embedded YouTube videos",
                "iframe1");
          }),
      WaitForState(kInterstitialDisplayed, true));
}

INSTANTIATE_TEST_SUITE_P(
    ,
    KidsProfileUiTest,
    testing::Values(FamilyLiveTest::RpcMode::kProd,
                    FamilyLiveTest::RpcMode::kTestImpersonation),
    [](const testing::TestParamInfo<FamilyLiveTest::RpcMode>& info) {
      return ToString(info.param);
    });

}  // namespace
}  // namespace supervised_user
