// Copyright 2015 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/page_info/chosen_object_view.h"

#include <memory>
#include <string_view>
#include <utility>

#include "base/functional/bind.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/views/controls/rich_controls_container_view.h"
#include "chrome/browser/ui/views/page_info/chosen_object_view_observer.h"
#include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
#include "chrome/browser/ui/views/page_info/page_info_view_factory.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/ui_base_features.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/label.h"

ChosenObjectView::ChosenObjectView(
    std::unique_ptr<PageInfoUI::ChosenObjectInfo> info,
    std::u16string display_name)
    : info_(std::move(info)) {
  SetUseDefaultFillLayout(true);
  row_view_ = AddChildView(std::make_unique<RichControlsContainerView>());
  row_view_->SetTitle(display_name);

  // Create the delete button. It is safe to use base::Unretained here
  // because the button is owned by this object.
  std::unique_ptr<views::ImageButton> delete_button =
      views::CreateVectorImageButton(base::BindRepeating(
          &ChosenObjectView::ExecuteDeleteCommand, base::Unretained(this)));
  delete_button->SetRequestFocusOnPress(true);
  delete_button->SetTooltipText(l10n_util::GetStringFUTF16(
      info_->ui_info->delete_tooltip_string_id, display_name));
  views::InstallCircleHighlightPathGenerator(delete_button.get());

  // Disable the delete button for policy controlled objects and display the
  // allowed by policy string below for |secondary_label|.
  std::unique_ptr<views::Label> secondary_label;
  if (info_->chooser_object->source ==
      content_settings::SettingSource::kPolicy) {
    delete_button->SetEnabled(false);
    row_view_->AddSecondaryLabel(l10n_util::GetStringUTF16(
        info_->ui_info->allowed_by_policy_description_string_id));
  } else {
    row_view_->AddSecondaryLabel(
        l10n_util::GetStringUTF16(info_->ui_info->description_string_id));
  }

  delete_button_ = row_view_->AddControl(std::move(delete_button));

  UpdateIconImage(/*is_deleted=*/false);
  views::SetImageFromVectorIconWithColor(
      delete_button_,
      features::IsRoundedIconsEnabled() ? vector_icons::kCloseIcon
                                        : vector_icons::kCloseRoundedOldIcon,
      {kColorPageInfoChosenObjectDeleteButtonIcon,
       kColorPageInfoChosenObjectDeleteButtonIconDisabled});

  // Set flex rule, defined in `RichControlsContainerView`, to wrap the subtitle
  // text but size the parent view to match the content.
  SetProperty(
      views::kFlexBehaviorKey,
      views::FlexSpecification(base::BindRepeating(
          &RichControlsContainerView::FlexRule, base::Unretained(row_view_))));
}

void ChosenObjectView::AddObserver(ChosenObjectViewObserver* observer) {
  observer_list_.AddObserver(observer);
}

ChosenObjectView::~ChosenObjectView() = default;

void ChosenObjectView::ResetPermission() {
  if (delete_button_->GetVisible()) {
    ExecuteDeleteCommand();
  }
}

void ChosenObjectView::ExecuteDeleteCommand() {
  // Policy-managed permissions cannot be deleted. This isn't normally
  // reachable but views::test::ButtonTestApi::NotifyClick doesn't check
  // before executing the PressedCallback.
  if (info_->chooser_object->source ==
      content_settings::SettingSource::kPolicy) {
    return;
  }

  // Change the icon to reflect the selected setting.
  UpdateIconImage(/*is_deleted=*/true);

  DCHECK(delete_button_->GetEnabled());
  DCHECK(delete_button_->GetVisible());
  delete_button_->SetVisible(false);

  // Hide the row after revoking access.
  SetVisible(false);

  observer_list_.Notify(&ChosenObjectViewObserver::OnChosenObjectDeleted,
                        *info_);
}

void ChosenObjectView::UpdateIconImage(bool is_deleted) const {
  row_view_->SetIcon(
      PageInfoViewFactory::GetChosenObjectIcon(*info_, is_deleted));
}

std::u16string_view ChosenObjectView::GetObjectNameForTesting() const {
  return row_view_->GetTitleForTesting();  // IN-TEST
}

views::ImageButton* ChosenObjectView::GetDeleteButtonForTesting() const {
  return delete_button_;
}

BEGIN_METADATA(ChosenObjectView)
END_METADATA
