// Copyright 2014 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/passwords/credentials_item_view.h"

#include <memory>
#include <utility>

#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/passwords/ui_utils.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/browser/ui/views/passwords/views_utils.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/affiliations/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/border.h"
#include "ui/views/bubble/tooltip_icon.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view_class_properties.h"

namespace {

}  // namespace

CredentialsItemView::CredentialsItemView(
    PressedCallback callback,
    const std::u16string& upper_text,
    const std::u16string& lower_text,
    const password_manager::PasswordForm* form,
    network::mojom::URLLoaderFactory* loader_factory,
    const url::Origin& initiator,
    int upper_text_style,
    int lower_text_style)
    : Button(std::move(callback)) {
  SetNotifyEnterExitOnChild(true);
  views::BoxLayout* layout =
      SetLayoutManager(std::make_unique<views::BoxLayout>(
          views::BoxLayout::Orientation::kHorizontal));
  layout->set_cross_axis_alignment(
      views::BoxLayout::CrossAxisAlignment::kCenter);
  layout->set_between_child_spacing(
      ChromeLayoutProvider::Get()->GetDistanceMetric(
          views::DISTANCE_RELATED_LABEL_HORIZONTAL));
  // Create an image-view for the avatar. Make sure it ignores events so that
  // the parent can receive the events instead.
  auto image_view = std::make_unique<CircularImageView>();
  image_view_ = image_view.get();
  image_view_->SetCanProcessEventsWithinSubtree(false);
  gfx::Image image = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE);
  DCHECK(image.Width() >= kAvatarImageSize &&
         image.Height() >= kAvatarImageSize);
  UpdateAvatar(image.AsImageSkia());
  if (form->icon_url.is_valid()) {
    // Fetch the actual avatar.
    AccountAvatarFetcher* fetcher = new AccountAvatarFetcher(
        form->icon_url, weak_ptr_factory_.GetWeakPtr());
    fetcher->Start(loader_factory, initiator);
  }
  AddChildView(std::move(image_view));

  // TODO(tapted): Check these (and the STYLE_ values below) against the spec on
  // http://crbug.com/41278269.
  const int kLabelContext = CONTEXT_DIALOG_BODY_TEXT_SMALL;

  views::View* text_container = nullptr;
  if (!upper_text.empty() || !lower_text.empty()) {
    text_container = AddChildView(std::make_unique<views::View>());
    views::BoxLayout* text_layout =
        text_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
            views::BoxLayout::Orientation::kVertical));
    text_layout->set_cross_axis_alignment(
        views::BoxLayout::CrossAxisAlignment::kStart);
    layout->SetFlexForView(text_container, 1);
  }

  if (!upper_text.empty()) {
    auto upper_label = std::make_unique<views::Label>(upper_text, kLabelContext,
                                                      upper_text_style);
    upper_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    upper_label_ = text_container->AddChildView(std::move(upper_label));
  }

  if (!lower_text.empty()) {
    auto lower_label = std::make_unique<views::Label>(lower_text, kLabelContext,
                                                      lower_text_style);
    lower_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    lower_label->SetMultiLine(true);
    lower_label_ = text_container->AddChildView(std::move(lower_label));
  }

  // Add info icon with a tooltip providing the source of the PSL, affiliated
  // and grouped credentials.
  if (form->match_type.has_value() &&
      password_manager_util::GetMatchType(*form) !=
          password_manager_util::GetLoginMatchType::kExact) {
    auto facet =
        affiliations::FacetURI::FromPotentiallyInvalidSpec(form->signon_realm);
    if (facet.IsValidAndroidFacetURI()) {
      std::u16string app_name = base::UTF8ToUTF16(form->app_display_name);
      if (app_name.empty()) {
        app_name = l10n_util::GetStringFUTF16(
            IDS_SETTINGS_PASSWORDS_ANDROID_APP,
            base::UTF8ToUTF16(facet.android_package_name()));
      }
      info_icon_ = AddChildView(std::make_unique<views::TooltipIcon>(app_name));
    } else {
      info_icon_ = AddChildView(std::make_unique<views::TooltipIcon>(
          base::UTF8ToUTF16(form->url.DeprecatedGetOriginAsURL().spec())));
    }
  }

  if (!upper_text.empty() && !lower_text.empty()) {
    GetViewAccessibility().SetName(upper_text + u"\n" + lower_text);
  } else {
    GetViewAccessibility().SetName(upper_text + lower_text);
  }

  SetFocusBehavior(FocusBehavior::ALWAYS);
  SetInstallFocusRingOnFocus(true);
  // With Focus Ring on Focus there is a line around the button.
  // We want to remove this line so setting the thickness as 0.
  views::FocusRing::Get(this)->SetHaloThickness(0.0f);
}

CredentialsItemView::~CredentialsItemView() = default;

void CredentialsItemView::UpdateAvatar(const gfx::ImageSkia& image) {
  image_view_->SetImage(
      ui::ImageModel::FromImageSkia(ScaleImageForAccountAvatar(image)));
}

int CredentialsItemView::GetPreferredHeight() const {
  return GetPreferredSize().height();
}

void CredentialsItemView::OnPaintBackground(gfx::Canvas* canvas) {
  if (GetState() == STATE_PRESSED || GetState() == STATE_HOVERED ||
      HasFocus()) {
    canvas->DrawColor(
        GetColorProvider()->GetColor(ui::kColorMenuItemBackgroundSelected));
  }
}

BEGIN_METADATA(CredentialsItemView)
END_METADATA
