// Copyright 2026 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/ui/sad_tab_controller.h"

#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/contents_web_view.h"
#include "chrome/browser/ui/views/sad_tab_view.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/view.h"
#include "ui/views/view_utils.h"

namespace {

ContentsWebView* FindContentsWebView(content::WebContents* web_contents) {
  tabs::TabInterface* tab =
      tabs::TabInterface::MaybeGetFromContents(web_contents);
  if (!tab) {
    return nullptr;
  }

  // In unit tests, browser->GetWindow() might not be a real BrowserView.
  BrowserWindowInterface* browser = tab->GetBrowserWindowInterface();
  if (!browser || !browser->GetWindow() ||
      !browser->GetWindow()->GetNativeWindow()) {
    return nullptr;
  }
  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
  DCHECK(browser_view);

  for (auto* contents_view : browser_view->GetAllVisibleContentsWebViews()) {
    if (contents_view->web_contents() == web_contents) {
      return contents_view;
    }
  }

  return nullptr;
}

}  // namespace

SadTabController::SadTabController(content::WebContents* web_contents,
                                   SadTabKind kind)
    : SadTab(web_contents, kind) {
  ReinstallInWebView();
}

SadTabController::~SadTabController() {
  ContentsWebView* contents_view = FindContentsWebView(web_contents());
  if (!contents_view) {
    return;
  }

  if (view_tracker_ && !owned_sad_tab_view_) {
    auto crashed_overlay_view = contents_view->DetachCrashedOverlayView();
    CHECK_EQ(view_tracker_.view(), crashed_overlay_view.get());
  }
}

void SadTabController::ReinstallInWebView() {
  std::unique_ptr<SadTabView> sad_tab_view;
  if (owned_sad_tab_view_) {
    sad_tab_view = std::move(owned_sad_tab_view_);
  } else if (view_tracker_) {
    // If the controller doesn't own the SadTabView, get ownership from its
    // parent.
    auto* parent = view_tracker_.view()->parent();
    sad_tab_view = views::AsViewClass<views::WebView>(parent)
                       ->DetachCrashedOverlayView<SadTabView>();
    CHECK(sad_tab_view);
  }

  ContentsWebView* contents_view = FindContentsWebView(web_contents());
  if (!contents_view) {
    owned_sad_tab_view_ = std::move(sad_tab_view);
    return;
  }

  if (!sad_tab_view) {
    sad_tab_view = std::make_unique<SadTabView>(
        this, kind(), GetTitle(), GetInfoMessage(), GetSubMessages(),
        GetErrorCodeFormatString(), GetCrashedErrorCode(), GetButtonTitle(),
        GetHelpLinkTitle());
    view_tracker_.SetView(sad_tab_view.get());
  }
  CHECK_EQ(view_tracker_.view(), sad_tab_view.get());
  sad_tab_view->SetBackgroundRadii(contents_view->GetBackgroundRadii());
  contents_view->TakeCrashedOverlayView(
      std::move(sad_tab_view),
      base::BindOnce(
          [](base::WeakPtr<SadTabController> controller,
             std::unique_ptr<views::View> crashed_overlay_view) {
            CHECK(!controller->owned_sad_tab_view_);
            std::unique_ptr<SadTabView> sad_tab_view =
                views::AsViewClass<SadTabView>(std::move(crashed_overlay_view));
            CHECK(sad_tab_view);
            controller->owned_sad_tab_view_.swap(sad_tab_view);
          },
          weak_factory_.GetWeakPtr()));
}

void SadTabController::SetBackgroundRadii(const gfx::RoundedCornersF& radii) {
  if (view_tracker_.view()) {
    views::AsViewClass<SadTabView>(view_tracker_.view())
        ->SetBackgroundRadii(radii);
  }
}

gfx::RoundedCornersF SadTabController::GetBackgroundRadii() const {
  if (view_tracker_) {
    return views::AsViewClass<SadTabView>(view_tracker_.view())
        ->GetBackgroundRadii();
  }
  return gfx::RoundedCornersF();
}

void SadTabController::RequestFocus() {
  if (view_tracker_) {
    view_tracker_.view()->RequestFocus();
  }
}

// SadTab::Create implementation moved here.
std::unique_ptr<SadTab> SadTab::Create(content::WebContents* web_contents,
                                       SadTabKind kind) {
  return std::make_unique<SadTabController>(web_contents, kind);
}
