// Copyright 2014 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/views/apps/app_info_dialog/app_info_dialog_container.h"

#include <utility>

#include "build/build_config.h"
#include "chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.h"
#include "chrome/common/buildflags.h"
#include "components/constrained_window/constrained_window_views.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/border.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/window/frame_view.h"
#include "ui/views/window/native_frame_view.h"

namespace {

#if BUILDFLAG(IS_MAC)
const ui::mojom::ModalType kModalType = ui::mojom::ModalType::kChild;
const views::BubbleBorder::Shadow kShadowType = views::BubbleBorder::NO_SHADOW;
#else
const ui::mojom::ModalType kModalType = ui::mojom::ModalType::kWindow;
const views::BubbleBorder::Shadow kShadowType =
    views::BubbleBorder::STANDARD_SHADOW;
#endif

constexpr gfx::Size kDialogSize = gfx::Size(380, 490);

// A BubbleFrameView that allows its client view to extend all the way to the
// top of the dialog, overlapping the BubbleFrameView's close button. This
// allows dialog content to appear closer to the top, in place of a title.
// TODO(estade): the functionality here should probably be folded into
// BubbleFrameView.
class FullSizeBubbleFrameView : public views::BubbleFrameView {
  METADATA_HEADER(FullSizeBubbleFrameView, views::BubbleFrameView)

 public:
  FullSizeBubbleFrameView()
      : views::BubbleFrameView(gfx::Insets(), gfx::Insets()) {}
  FullSizeBubbleFrameView(const FullSizeBubbleFrameView&) = delete;
  FullSizeBubbleFrameView& operator=(const FullSizeBubbleFrameView&) = delete;
  ~FullSizeBubbleFrameView() override = default;

 private:
  // Overridden from views::BubbleFrameView:
  bool ExtendClientIntoTitle() const override { return true; }
};

BEGIN_METADATA(FullSizeBubbleFrameView)
END_METADATA

}  // namespace

// A container view for a native dialog, which sizes to the given fixed |size|.
class NativeDialogContainer : public views::DialogDelegateView {
  METADATA_HEADER(NativeDialogContainer, views::DialogDelegateView)

 public:
  NativeDialogContainer(std::unique_ptr<views::View> dialog_body,
                        const gfx::Size& size,
                        base::OnceClosure close_callback) {
    SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone));
    SetModalType(kModalType);
    AddChildView(std::move(dialog_body));
    SetLayoutManager(std::make_unique<views::FillLayout>());
    SetPreferredSize(size);

    if (!close_callback.is_null()) {
      RegisterWindowClosingCallback(std::move(close_callback));
    }
  }
  NativeDialogContainer(const NativeDialogContainer&) = delete;
  NativeDialogContainer& operator=(const NativeDialogContainer&) = delete;
  ~NativeDialogContainer() override = default;

 private:
  // Overridden from views::WidgetDelegate:
  std::unique_ptr<views::FrameView> CreateFrameView(
      views::Widget* widget) override {
    auto frame = std::make_unique<FullSizeBubbleFrameView>();
    frame->SetBubbleBorder(std::make_unique<views::BubbleBorder>(
        views::BubbleBorder::FLOAT, kShadowType));
    return frame;
  }
};

BEGIN_METADATA(NativeDialogContainer)
END_METADATA

void ShowAppInfoInNativeDialog(content::WebContents* web_contents,
                               Profile* profile,
                               const extensions::Extension* app,
                               base::OnceClosure close_callback) {
  views::DialogDelegate* dialog =
      new NativeDialogContainer(std::make_unique<AppInfoDialog>(profile, app),
                                kDialogSize, std::move(close_callback));
  views::Widget* dialog_widget;
  if (dialog->GetModalType() == ui::mojom::ModalType::kChild) {
    dialog_widget =
        constrained_window::ShowWebModalDialogViews(dialog, web_contents);
  } else {
    gfx::NativeWindow window = web_contents->GetTopLevelNativeWindow();
    dialog_widget =
        constrained_window::CreateBrowserModalDialogViews(dialog, window);
    dialog_widget->Show();
  }
}
