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

#include "ash/wm/window_mini_view_header_view.h"

#include "ash/style/ash_color_id.h"
#include "ash/wm/window_mini_view.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_constants.h"
#include "chromeos/ui/base/window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer_solid_color.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/background.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/view_observer.h"

namespace ash {

namespace {

// The font delta of the window title.
constexpr int kLabelFontDelta = 2;

// Padding between header items.
constexpr int kHeaderPaddingDp = 8;

// The size in dp of the window icon shown on the alt-tab/overview window next
// to the title.
constexpr gfx::Size kIconSize = gfx::Size(24, 24);

constexpr gfx::Insets kHeaderInsets = gfx::Insets::TLBR(0, 10, 0, 10);

std::u16string GetWindowTitle(aura::Window* window) {
  aura::Window* transient_root = wm::GetTransientRoot(window);
  const std::u16string* overview_title =
      transient_root->GetProperty(chromeos::kWindowOverviewTitleKey);
  return (overview_title && !overview_title->empty())
             ? *overview_title
             : transient_root->GetTitle();
}

}  // namespace

WindowMiniViewHeaderView::~WindowMiniViewHeaderView() = default;

WindowMiniViewHeaderView::WindowMiniViewHeaderView(
    WindowMiniView* window_mini_view)
    : window_mini_view_(window_mini_view) {
  SetOrientation(views::BoxLayout::Orientation::kVertical);

  // This is to apply the rounded corners to child layers.
  SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  layer()->SetIsFastRoundedCorner(true);

  // Box layout should accomplish the following:
  // +------+-------+-------------------------------------------------+--------+
  // | icon | label |               leftover space                    | close  |
  // |      |       |                                                 | button |
  // +------+-------+-------------------------------------------------+--------+
  // * Note the close button may not be present in some corner cases, so it's
  //   created outside of `WindowMiniViewHeaderView`.
  // 1) The icon and close button get their preferred sizes.
  // 2) If the label's preferred size fits between the icon and close button,
  //    blank space is added between the label and close button until the close
  //    button is right aligned.
  // 3) If the label's preferred size doesn't fit between the icon and close
  //    button, it gets shrunk until it fits (leftover space above is zero).
  icon_label_view_ = AddChildView(std::make_unique<views::BoxLayoutView>());
  icon_label_view_->SetOrientation(views::BoxLayout::Orientation::kHorizontal);
  icon_label_view_->SetInsideBorderInsets(kHeaderInsets);
  icon_label_view_->SetBetweenChildSpacing(kHeaderPaddingDp);

  title_label_ = icon_label_view_->AddChildView(std::make_unique<views::Label>(
      GetWindowTitle(window_mini_view_->source_window())));
  title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  title_label_->SetAutoColorReadabilityEnabled(false);
  title_label_->SetSubpixelRenderingEnabled(false);
  title_label_->SetFontList(gfx::FontList().Derive(
      kLabelFontDelta, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
  title_label_->SetEnabledColor(cros_tokens::kCrosSysPrimary);
  title_label_->SetPaintToLayer();
  title_label_->layer()->SetFillsBoundsOpaquely(false);
  icon_label_view_->SetFlexForView(title_label_, 1);

  RefreshHeaderViewRoundedCorners();

  separator_ = AddChildView(std::make_unique<views::View>());
  separator_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  separator_->SetPreferredSize(gfx::Size(1, views::Separator::kThickness));

  SetFlexForView(icon_label_view_, 1);
}

void WindowMiniViewHeaderView::UpdateIconView(aura::Window* window) {
  aura::Window* transient_root = wm::GetTransientRoot(window);
  // Prefer kAppIconKey over kWindowIconKey as the app icon is typically
  // larger.
  gfx::ImageSkia* icon = transient_root->GetProperty(aura::client::kAppIconKey);
  if (!icon || icon->size().IsEmpty()) {
    icon = transient_root->GetProperty(aura::client::kWindowIconKey);
  }
  if (!icon) {
    return;
  }

  if (!icon_view_) {
    icon_view_ = icon_label_view_->AddChildViewAt(
        std::make_unique<views::ImageView>(), 0);
    icon_view_->SetPaintToLayer();
    icon_view_->layer()->SetFillsBoundsOpaquely(false);
  }

  icon_view_->SetImage(ui::ImageModel::FromImageSkia(
      gfx::ImageSkiaOperations::CreateResizedImage(
          *icon, skia::ImageOperations::RESIZE_BEST, kIconSize)));
}

void WindowMiniViewHeaderView::UpdateTitleLabel(aura::Window* window) {
  title_label_->SetText(GetWindowTitle(window));
}

void WindowMiniViewHeaderView::RefreshHeaderViewRoundedCorners() {
  const int default_corner_radius = kWindowMiniViewCornerRadius;
  const gfx::RoundedCornersF new_rounded_corners =
      custom_header_view_rounded_corners_.value_or(gfx::RoundedCornersF(
          default_corner_radius, default_corner_radius, 0, 0));
  if (current_header_view_rounded_corners_ &&
      *current_header_view_rounded_corners_ == new_rounded_corners) {
    return;
  }
  current_header_view_rounded_corners_ = new_rounded_corners;
  layer()->SetRoundedCornerRadius(new_rounded_corners);
}

void WindowMiniViewHeaderView::SetHeaderViewRoundedCornerRadius(
    gfx::RoundedCornersF& header_view_rounded_corners) {
  custom_header_view_rounded_corners_ = header_view_rounded_corners;
  RefreshHeaderViewRoundedCorners();
}

void WindowMiniViewHeaderView::ResetRoundedCorners() {
  custom_header_view_rounded_corners_.reset();
  RefreshHeaderViewRoundedCorners();
}

void WindowMiniViewHeaderView::OnThemeChanged() {
  View::OnThemeChanged();
  CHECK(GetColorProvider());
  layer()->AsSolidColor()->SetColor(SkColor4f::FromColor(
      GetColorProvider()->GetColor(cros_tokens::kCrosSysHeader)));
  separator_->layer()->AsSolidColor()->SetColor(SkColor4f::FromColor(
      GetColorProvider()->GetColor(kColorAshWindowHeaderStrokeColor)));
}

BEGIN_METADATA(WindowMiniViewHeaderView)
END_METADATA

}  // namespace ash
