// 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.

#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_CUSTOM_CORNERS_BACKGROUND_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_CUSTOM_CORNERS_BACKGROUND_H_

#include <variant>
#include <vector>

#include "base/types/strong_alias.h"
#include "chrome/browser/ui/views/frame/custom_corners.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/interaction/safe_castable.h"
#include "ui/color/color_id.h"
#include "ui/color/color_variant.h"
#include "ui/views/background.h"
#include "ui/views/view.h"

class BrowserView;

// Represents a background with corners that can either be square, rounded, or
// rounded with a background color behind them.
//
// Used by a number of top-level browser elements to prevent overdrawing the
// browser's corners or providing nice curved interfaces between elements.
class CustomCornersBackground : public views::Background, public CustomCorners {
 public:
  DECLARE_SAFE_CAST_TARGET()

  // Specifies how a corner should be painted.
  enum class CornerType {
    // Paint all the way to the corner.
    kSquare,
    // Paint only a rounded corner, leaving the actual corner transparent.
    kRounded,
    // Paint a rounded corner with a background color behind.
    kRoundedWithBackground
  };

  // Represents each corner. If `radius` is not specified it will default to
  // `TOOLBAR_CORNER_RADIUS`.
  struct Corner {
    CornerType type = CornerType::kSquare;
    std::optional<int> radius;

    bool operator==(const Corner&) const = default;
  };
  using Corners = CornerMapT<CornerOrientation, Corner>;

  // Specifies whether outline strokes should be drawn.
  struct Outline {
    ColorWithAlpha color;
    bool top = false;
    bool leading = false;
    bool bottom = false;
    bool trailing = false;

    bool has_strokes() const {
      return color.is_visible() && (top || leading || bottom || trailing);
    }

    friend bool operator==(const Outline& left, const Outline& right) = default;
  };

  // Struct to store corner radii.
  using CornerRadii = std::array<SkVector, 4>;

  CustomCornersBackground(views::View& view,
                          BrowserView& browser_view,
                          ColorChoiceWithAlpha primary_color,
                          ColorChoiceWithAlpha corner_color,
                          std::optional<int> default_radius = std::nullopt);
  CustomCornersBackground(views::View& view,
                          BrowserView& browser_view,
                          ColorChoice primary_color,
                          ColorChoice corner_color,
                          std::optional<int> default_radius = std::nullopt);
  ~CustomCornersBackground() override;

  // Sets whether the background should be painted.
  void SetVisible(bool visible);

  // Sets the color to paint the primary area of the view.
  void SetPrimaryColor(ColorChoiceWithAlpha primary_color);
  void SetPrimaryColor(ColorChoice primary_color) {
    SetPrimaryColor(ColorChoiceWithAlpha(primary_color));
  }
  ColorChoiceWithAlpha primary_color() const { return primary_color_; }

  // Sets the color to paint behind corners of type `kRoundedWithBackground`;
  // default is `FrameColor`.
  void SetCornerColor(ColorChoiceWithAlpha corner_color);

  // Sets the corners to use.
  void SetCorners(const Corners& corners);

  // Sets the outline strokes to use.
  void SetOutline(const Outline& outline);

  // Returns an appropriate window corner for the current platform.
  // Specify `upper` to switch between upper (true) and lower (false) corners,
  // as they may be different on some platforms.
  Corner GetWindowCorner(bool upper) const;

  // Sets whether to create an artificial glass effect behind the background.
  // Has no effect if glass is disabled or if artificial glass is set to opaque.
  // Setting to true requires the following:
  //  - Host view has a layer.
  //  - Corners have already been updated for the current frame.
  void SetUseBackgroundBlur(bool use_background_blur);

  bool visible_for_testing() const { return visible_; }

  // Takes the inverse of a view with a CustomCornersBackground - i.e. it cuts
  // out the corners, not the background area.
  struct InverseOf {
    InverseOf() = default;
    explicit InverseOf(const CustomCornersBackground& background_)
        : background(&background_) {}
    InverseOf(const InverseOf& other) = default;
    InverseOf& operator=(const InverseOf& other) = default;
    ~InverseOf() = default;

    raw_ptr<const CustomCornersBackground> background = nullptr;
  };
  using Cutout = std::variant<InverseOf, const views::View*>;
  using Cutouts = std::vector<Cutout>;

  [[nodiscard]] inline SkPath GetBackgroundPath() const {
    return GetBackgroundPath(view_->GetLocalBounds(), nullptr);
  }

  // Cuts `cutouts` out of `this`. Works for views with a
  // `CustomCornersBackground` as well as for `CustomFloatingCorner`. Empty
  // clears the cutout.
  void SetCutoutFrom(const Cutouts& cutouts);

  // views::Background:
  void Paint(gfx::Canvas* canvas, views::View* view) const override;
  void OnViewThemeChanged(views::View* view) override;
  std::optional<gfx::RoundedCornersF> GetRoundedCornerRadii() const override;

  // CustomCorners:
  const views::View& GetView() const override;
  void OnBrowserPaintAsActiveChanged() override;
  void SchedulePaintHost() override;

  int default_radius() const { return default_radius_; }

 private:
  // Hide this as it should not be used directly.
  using Background::SetColor;

  using VisualCorners = CornerMapT<VisualCorner, Corner>;

  // Returns a path containing the entire painted background region.
  SkPath GetBackgroundPath(const gfx::Rect& in_bounds,
                           CornerRadii* corners = nullptr) const;

  // Returns a set of paths containining each corner cutout.
  std::vector<SkPath> GetCornerPaths(const gfx::Rect& in_bounds) const;

  // Possibly mirrors corners for RtL.
  VisualCorners GetMirroredCorners() const;

  // Possibly mirrors outline for RtL.
  Outline GetMirroredOutline() const;

  bool visible_ = true;
  ColorChoiceWithAlpha primary_color_;
  ColorChoiceWithAlpha corner_color_;
  int default_radius_;
  Corners corners_;
  Outline outline_;
  std::vector<SkPath> cutout_paths_;
  const raw_ref<views::View> view_;
};

#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_CUSTOM_CORNERS_BACKGROUND_H_
