// Copyright 2024 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/toasts/api/toast_specification.h"

#include <memory>

#include "base/check.h"
#include "base/functional/callback.h"
#include "base/types/pass_key.h"
#include "ui/menus/simple_menu_model.h"

ToastSpecification::Builder::Builder(const gfx::VectorIcon& icon,
                                     int body_string_id)
    : toast_specification_(
          std::make_unique<ToastSpecification>(base::PassKey<Builder>(),
                                               icon,
                                               body_string_id)) {}

ToastSpecification::Builder::Builder(const gfx::VectorIcon& icon)
    : toast_specification_(
          std::make_unique<ToastSpecification>(base::PassKey<Builder>(),
                                               icon)) {}
ToastSpecification::Builder::~Builder() {
  // Verify that ToastSpecification::Builder::Build() has been called
  // so the toast specification is completely built.
  CHECK(!toast_specification_);
}

ToastSpecification::Builder& ToastSpecification::Builder::AddCloseButton() {
  toast_specification_->AddCloseButton();
  return *this;
}

ToastSpecification::Builder& ToastSpecification::Builder::AddActionButton(
    int action_button_string_id,
    base::RepeatingClosure closure) {
  toast_specification_->AddActionButton(action_button_string_id,
                                        std::move(closure));
  return *this;
}

ToastSpecification::Builder& ToastSpecification::Builder::AddMenu() {
  toast_specification_->AddMenu();
  return *this;
}

ToastSpecification::Builder& ToastSpecification::Builder::AddGlobalScoped() {
  toast_specification_->AddGlobalScope();
  return *this;
}

ToastSpecification::Builder&
ToastSpecification::Builder::SetPersistOnNavigation() {
  toast_specification_->SetPersistOnNavigation();
  return *this;
}

ToastSpecification::Builder&
ToastSpecification::Builder::SetToastAsActionable() {
  toast_specification_->SetToastAsActionable();
  return *this;
}

std::unique_ptr<ToastSpecification> ToastSpecification::Builder::Build() {
  ValidateSpecification();
  return std::move(toast_specification_);
}

void ToastSpecification::Builder::ValidateSpecification() {
  // Toasts with an action button must have a close button and not a menu.
  if (toast_specification_->action_button_string_id().has_value()) {
    CHECK(toast_specification_->has_close_button());
    CHECK(!toast_specification_->has_menu());
  }

  // Toasts with a menu can't have a close button. If this behavior is needed,
  // discuss with UX how to design this in a way that supports both.
  if (toast_specification_->has_menu()) {
    CHECK(!toast_specification_->has_close_button());
  }

  // Toasts can be manually set as actionable, or have close / menu buttons. Not
  // both.
  if (toast_specification_->has_actionable_override()) {
    CHECK(!toast_specification_->has_close_button() &&
          !toast_specification_->has_menu())
        << "Avoid use of SetToastAsActionable() on an already actionable toast";
  }
}

ToastSpecification::ToastSpecification(
    base::PassKey<ToastSpecification::Builder>,
    const gfx::VectorIcon& icon,
    int string_id)
    : icon_(icon), body_string_id_(string_id) {}

ToastSpecification::ToastSpecification(
    base::PassKey<ToastSpecification::Builder>,
    const gfx::VectorIcon& icon)
    : icon_(icon) {}

ToastSpecification::~ToastSpecification() = default;

void ToastSpecification::AddCloseButton() {
  has_close_button_ = true;
}

void ToastSpecification::AddActionButton(int string_id,
                                         base::RepeatingClosure closure) {
  CHECK(!closure.is_null());
  action_button_string_id_ = string_id;
  action_button_closure_ = std::move(closure);
}

void ToastSpecification::AddMenu() {
  has_menu_ = true;
}

void ToastSpecification::AddGlobalScope() {
  is_global_scope_ = true;
}

void ToastSpecification::SetPersistOnNavigation() {
  persist_on_navigation_ = true;
}

void ToastSpecification::SetToastAsActionable() {
  actionable_toast_override_ = true;
}
