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

#ifndef ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_
#define ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_

#include "ash/ash_export.h"
#include "ash/style/icon_button.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"

namespace ash {

// The main button used in FeatureTilesContainerView, which acts as an entry
// point for features in QuickSettingsView.

// There are two TileTypes: Primary and Compact.

// The primary tile has an icon and title, and may have a subtitle and a
// drill-in button. It presents one of the following behaviors:
// 1. Launch surface        (e.g. Screen Capture)
// 2. Toggle                (e.g. Toggle Dark Theme)
// 3. Drill-in              (e.g. Go to Accessibility detailed view)
// 4. Toggle with drill-in  (e.g. Toggle Wi-Fi | Go to Network detailed view)
// 5. Togglable tile with decorative drill-in (e.g. Selecting a VPN network)

// The compact tile has an icon and a single title, which may be
// multi-line. They are always placed in pairs side by side to take up the
// space of a regular FeatureTile. Regular tiles may switch to their compact
// version when necessary, e.g. when entering TabletMode. It presents one
// of the following behaviors:
// 1. Launch surface        (e.g. Screen Capture)
// 2. Toggle                (e.g. Toggle Auto-rotate)
// 3. Drill-in              (e.g. Go to Cast detailed view)
class ASH_EXPORT FeatureTile : public views::Button {
 public:
  METADATA_HEADER(FeatureTile);

  // Used in the FeatureTile constructor to set the tile view type.
  enum class TileType {
    kPrimary = 0,
    kCompact = 1,
    kMaxValue = kCompact,
  };

  // Constructor for FeatureTiles. `callback` will be called when interacting
  // with the main part of the button, which accounts for the whole tile.
  // For primary tiles with drill-in, `callback` is called when interacting with
  // the left side of the button, since the right side holds the drill-in
  // button.
  explicit FeatureTile(base::RepeatingCallback<void()> callback,
                       bool is_togglable = true,
                       TileType type = TileType::kPrimary);
  FeatureTile(const FeatureTile&) = delete;
  FeatureTile& operator=(const FeatureTile&) = delete;
  ~FeatureTile() override;

  // Creates child views of Feature Tile. The constructed view will vary
  // depending on the button's `type_`.
  void CreateChildViews();

  // Creates `drill_in_button_` which holds `the drill_in_arrow_` icon button,
  // and is positioned in the right area of the feature tile.
  // `callback` is triggered when interacting with the drill-in button, but
  // focus is set on its child `drill_in_arrow_`.
  void CreateDrillInButton(base::RepeatingCallback<void()> callback,
                           const std::u16string& tooltip_text);

  // Creates a `drill_in_button_` that is not clickable but exists to indicate
  // the button shows a detailed view when pressed. Events will be processed by
  // its parent `FeatureTile`.
  void CreateDecorativeDrillInButton(const std::u16string& tooltip_text);

  TileType tile_type() { return type_; }

  // Updates the colors of the background and elements of the button.
  void UpdateColors();

  // Updates the `toggled_` state of the button. If button is not togglable,
  // `toggled_` will always be false.
  void SetToggled(bool toggled);
  bool IsToggled() const;

  // Sets the vector icon.
  void SetVectorIcon(const gfx::VectorIcon& icon);

  // Sets the tile icon from an ImageSkia.
  void SetImage(gfx::ImageSkia image);

  // Sets the text of `label_`.
  void SetLabel(const std::u16string& label);

  // Sets the text of the `sub_label_`.
  void SetSubLabel(const std::u16string& sub_label);

  // Sets visibility of `sub_label_`.
  void SetSubLabelVisibility(bool visible);

  // Sets the tooltip text of `drill_in_button_`.
  void SetDrillInButtonTooltipText(const std::u16string& text);

  // views::View:
  void OnThemeChanged() override;

  views::ImageView* icon() { return icon_; }
  views::Label* label() { return label_; }
  views::Label* sub_label() { return sub_label_; }
  views::LabelButton* drill_in_button() { return drill_in_button_; }
  IconButton* drill_in_arrow() { return drill_in_arrow_; }

 private:
  friend class BluetoothFeaturePodControllerTest;
  friend class NotificationCounterViewTest;

  // Updates `drill_in_arrow_` since it uses a different focus ring color when
  // the tile is toggled to provide contrast with the background color.
  void UpdateDrillInButtonFocusRingColor();

  // Creates the drill-in button related views. Will style the button as
  // decorative if an empty callback is provided.
  void CreateDrillInButtonView(base::RepeatingClosure callback,
                               const std::u16string& tooltip_text);

  // The vector icon for the tile, if one is set.
  raw_ptr<const gfx::VectorIcon, ExperimentalAsh> vector_icon_ = nullptr;

  // Owned by views hierarchy.
  raw_ptr<views::ImageView, ExperimentalAsh> icon_ = nullptr;
  raw_ptr<views::Label, ExperimentalAsh> label_ = nullptr;
  raw_ptr<views::Label, ExperimentalAsh> sub_label_ = nullptr;
  raw_ptr<views::LabelButton, ExperimentalAsh> drill_in_button_ = nullptr;
  raw_ptr<IconButton, ExperimentalAsh> drill_in_arrow_ = nullptr;

  // Whether this button is togglable.
  bool is_togglable_ = false;

  // Whether the button is currently toggled.
  bool toggled_ = false;

  // The type of the feature tile that determines how it lays out its view.
  TileType type_;

  // Used to update tile colors and to set the drill-in button enabled state
  // when the button state changes.
  base::CallbackListSubscription enabled_changed_subscription_;

  base::WeakPtrFactory<FeatureTile> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_