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

#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_VIEW_CHROMEOS_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_VIEW_CHROMEOS_H_

#include <memory>

#include "base/cancelable_callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/immersive/immersive_mode_controller.h"
#include "chrome/browser/ui/views/frame/browser_frame_header_chromeos.h"
#include "chrome/browser/ui/views/frame/browser_frame_view.h"
#include "chrome/browser/ui/views/tab_icon_view_model.h"
#include "chromeos/ui/frame/highlight_border_overlay.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_update.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/display/display_observer.h"
#include "ui/display/tablet_state.h"
#include "ui/gfx/geometry/rounded_corners_f.h"

class ProfileIndicatorIcon;
class TabIconView;

namespace chromeos {
class FrameCaptionButtonContainerView;
class HighlightBorderOverlay;
}  // namespace chromeos

// Provides the BrowserFrameView for Chrome OS.
class BrowserFrameViewChromeOS
    : public BrowserFrameView,
      public BrowserFrameHeaderChromeOS::AppearanceProvider,
      public display::DisplayObserver,
      public TabIconViewModel,
      public aura::WindowObserver,
      public ImmersiveModeController::Observer,
      public apps::AppRegistryCache::Observer {
  METADATA_HEADER(BrowserFrameViewChromeOS, BrowserFrameView)

 public:
  BrowserFrameViewChromeOS(BrowserWidget* frame, BrowserView* browser_view);
  BrowserFrameViewChromeOS(const BrowserFrameViewChromeOS&) = delete;
  BrowserFrameViewChromeOS& operator=(const BrowserFrameViewChromeOS&) = delete;
  ~BrowserFrameViewChromeOS() override;

  static BrowserFrameViewChromeOS* Get(aura::Window* window);

  void Init();

  // BrowserFrameView:
  BrowserLayoutParams GetBrowserLayoutParams() const override;
  bool ShouldShowWebAppFrameToolbar() const override;
  int GetTopInset(bool restored) const override;
  void UpdateThrobber(bool running) override;
  SkColor GetCaptionColor(BrowserFrameActiveState active_state) const override;
  SkColor GetFrameColor(BrowserFrameActiveState active_state) const override;
  void UpdateMinimumSize() override;
  gfx::RoundedCornersF GetWindowRoundedCorners() const override;

  // views::FrameView:
  gfx::Rect GetBoundsForClientView() const override;
  gfx::Rect GetWindowBoundsForClientBounds(
      const gfx::Rect& client_bounds) const override;
  int NonClientHitTest(const gfx::Point& point) override;
  void ResetWindowControls() override;
  void WindowControlsOverlayEnabledChanged() override;
  void UpdateWindowIcon() override;
  void UpdateWindowTitle() override;
  void SizeConstraintsChanged() override;
  void UpdateWindowRoundedCorners() override;

  // views::View:
  void OnPaint(gfx::Canvas* canvas) override;
  void Layout(PassKey) override;
  gfx::Size GetMinimumSize() const override;
  void OnThemeChanged() override;
  void ChildPreferredSizeChanged(views::View* child) override;
  views::View::Views GetChildrenInZOrder() override;

  // BrowserFrameHeaderChromeOS::AppearanceProvider:
  SkColor GetTitleColor() override;
  SkColor GetFrameHeaderColor(bool active) override;
  gfx::ImageSkia GetFrameHeaderImage(bool active) override;
  int GetFrameHeaderImageYInset() override;
  gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) override;

  // display::DisplayObserver:
  void OnDisplayTabletStateChanged(display::TabletState state) override;
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  void OnTabletModeToggled(bool enabled);

  // TabIconViewModel:
  bool ShouldTabIconViewAnimate() const override;
  ui::ImageModel GetFaviconForTabIconView() override;

  // aura::WindowObserver:
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;

  // ImmersiveModeController::Observer:
  void OnImmersiveFullscreenEntered() override;
  void OnImmersiveFullscreenExited() override;

  // apps::AppRegistryCache::Observer:
  void OnAppUpdate(const apps::AppUpdate& update) override;
  void OnAppRegistryCacheWillBeDestroyed(
      apps::AppRegistryCache* cache) override;

  // Helper to check whether we should enable immersive mode in current state.
  bool ShouldEnableImmersiveModeController() const;

  // Returns true to show if the user avatar should be shown.
  // Exposed for testing purpose.
  static bool ShouldShowAvatarForTesting(aura::Window* window);

  chromeos::FrameCaptionButtonContainerView* caption_button_container() {
    return caption_button_container_;
  }

  // Returns whether the associated window is in a locked fullscreen state.
  bool IsLockedFullscreen() const;

 protected:
  // BrowserFrameView:
  void PaintAsActiveChanged() override;
  void AddedToWidget() override;
  BoundsAndMargins GetCaptionButtonBounds() const override;

 private:
  friend class BrowserFrameViewChromeOSTestApi;
  FRIEND_TEST_ALL_PREFIXES(ImmersiveModeBrowserViewTest, ImmersiveFullscreen);
  class ProfileChangeObserver;

  // App is a PWA and has unframed in its manifest. This doesn't yet mean
  // that the `window-management` permission has been granted and unframed
  // mode would be activated.
  bool AppIsPwaWithUnframedDisplayMode() const;

  // Returns true if `GetShowCaptionButtonsWhenNotInOverview()` returns true
  // and this browser window is not showing in overview.
  bool GetShowCaptionButtons() const;

  // Returns whether we should show caption buttons. False for fullscreen,
  // tablet mode and webUI tab strip in most cases. The exceptions are if this
  // is a packaged app, as they have immersive mode enabled, and floated windows
  // in tablet mode.
  bool GetShowCaptionButtonsWhenNotInOverview() const;

  // Distance between the edge of the FrameView and the web app frame
  // toolbar.
  int GetToolbarLeftInset() const;

  // Distance between the edges of the FrameView and the tab strip.
  int GetTabStripLeftInset() const;
  int GetTabStripRightInset() const;

  // Returns true if there is anything to paint. Some fullscreen windows do
  // not need their frames painted.
  bool GetShouldPaint() const;

  // Helps to hide or show the header as needed when the window is added to or
  // removed from overview.
  void OnAddedToOrRemovedFromOverview();

  // Creates the frame header for the browser window.
  std::unique_ptr<chromeos::FrameHeader> CreateFrameHeader();

  // Triggers the web-app origin and icon animations, assumes the web-app UI
  // elements exist.
  void StartWebAppAnimation();

  // Updates the kTopViewInset window property after a layout.
  void UpdateTopViewInset();

  // Returns the target height of the header.
  int GetTargetHeaderHeight() const;

  // Returns true if |profile_indicator_icon_| should be shown.
  bool GetShowProfileIndicatorIcon() const;

  // Updates the icon that indicates a teleported window.
  void UpdateProfileIcons();

  void MaybeAddAppIconToLayoutParams(BrowserLayoutParams& params) const;

  void LayoutProfileIndicator();

  void UpdateUnframedModeEnabled();

  void RelayoutBrowserWindow();

  ImmersiveModeController* GetImmersiveModeController() const;

  // Returns whether this window is currently in the overview list.
  bool GetOverviewMode() const;

  // Returns whether this window is currently in, or is about to be in, tab
  // fullscreen (not immersive fullscreen). Returns false for immersive
  // fullscreen.
  bool GetHideCaptionButtonsForFullscreen() const;

  // Called any time the frame color may have changed.
  void OnUpdateFrameColor();

  // Returns whether the associated window is currently floated or not.
  bool IsFloated() const;

  // Returns whether the associated window is currently snapped or not.
  bool IsSnapped() const;

  // Returns the top level aura::Window for this browser window.
  const aura::Window* GetFrameWindow() const;
  aura::Window* GetFrameWindow();

  // Generates a nine patch layer painted with a highlight border.
  std::unique_ptr<HighlightBorderOverlay> highlight_border_overlay_;

  // View which contains the window controls.
  raw_ptr<chromeos::FrameCaptionButtonContainerView> caption_button_container_ =
      nullptr;

  // For popups, the window icon.
  raw_ptr<TabIconView> window_icon_ = nullptr;

  // This is used for teleported windows (in multi-profile mode).
  raw_ptr<ProfileIndicatorIcon> profile_indicator_icon_ = nullptr;

  // Helper class for painting the header.
  std::unique_ptr<chromeos::FrameHeader> frame_header_;

  base::ScopedObservation<aura::Window, aura::WindowObserver>
      window_observation_{this};

  base::ScopedObservation<apps::AppRegistryCache,
                          apps::AppRegistryCache::Observer>
      app_registry_cache_observation_{this};

  std::optional<display::ScopedDisplayObserver> display_observer_;

  gfx::Size last_minimum_size_;
};

#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_VIEW_CHROMEOS_H_
