// Copyright 2025 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/actor/actor_keyed_service_fake.h"

#include "base/test/bind.h"
#include "chrome/browser/actor/actor_task.h"
#include "chrome/browser/actor/actor_test_util.h"
#include "chrome/browser/actor/execution_engine.h"
#include "chrome/browser/actor/ui/actor_ui_state_manager_interface.h"
#include "chrome/browser/actor/ui/event_dispatcher.h"
#include "chrome/browser/actor/ui/test_support/mock_event_dispatcher.h"
#include "chrome/browser/actor/ui/ui_event.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/actor/action_result.h"
#include "chrome/common/actor_webui.mojom.h"

namespace actor {
using ::testing::_;

ActorKeyedServiceFake::ActorKeyedServiceFake(Profile* profile)
    : ActorKeyedService(profile) {}

ActorKeyedServiceFake::~ActorKeyedServiceFake() = default;

TaskId ActorKeyedServiceFake::CreateTaskForTesting() {
  return CreateTaskWithDurationAndFeatureModeForTesting(  // IN-TEST
      actor::webui::mojom::TaskDuration::kDefault,
      glic::mojom::FeatureMode::kUnspecified);
}

TaskId ActorKeyedServiceFake::CreateTransientTaskForTesting() {
  return CreateTaskWithDurationAndFeatureModeForTesting(  // IN-TEST
      actor::webui::mojom::TaskDuration::kTransient,
      glic::mojom::FeatureMode::kUnspecified);
}

TaskId ActorKeyedServiceFake::CreateExperimentalTriggeringTaskForTesting() {
  return CreateTaskWithDurationAndFeatureModeForTesting(  // IN-TEST
      actor::webui::mojom::TaskDuration::kDefault,
      glic::mojom::FeatureMode::kExperimentalTriggering);
}

TaskId ActorKeyedServiceFake::CreateTaskWithDurationForTesting(  // IN-TEST
    actor::webui::mojom::TaskDuration duration) {
  return CreateTaskWithDurationAndFeatureModeForTesting(  // IN-TEST
      duration, glic::mojom::FeatureMode::kUnspecified);
}

TaskId ActorKeyedServiceFake::
    CreateTaskWithDurationAndFeatureModeForTesting(  // IN-TEST
        actor::webui::mojom::TaskDuration duration,
        glic::mojom::FeatureMode feature_mode) {
  std::unique_ptr<ui::UiEventDispatcher> ui_event_dispatcher =
      ui::NewMockUiEventDispatcher();
  std::unique_ptr<ui::UiEventDispatcher> task_ui_event_dispatcher =
      ui::NewMockUiEventDispatcher();

  auto* mock_ui_dispatcher =
      static_cast<ui::MockUiEventDispatcher*>(ui_event_dispatcher.get());
  auto* mock_task_ui_dispatcher =
      static_cast<ui::MockUiEventDispatcher*>(task_ui_event_dispatcher.get());

  for (auto& mock : {mock_ui_dispatcher, mock_task_ui_dispatcher}) {
    ON_CALL(*mock, OnPreTool(_, _))
        .WillByDefault(
            UiEventDispatcherCallback<ToolRequest>(base::BindRepeating(
                MakeOkResult, /*requires_page_stabilization=*/true)));
    ON_CALL(*mock, OnPostTool(_, _))
        .WillByDefault(
            UiEventDispatcherCallback<ToolRequest>(base::BindRepeating(
                MakeOkResult, /*requires_page_stabilization=*/true)));
    ON_CALL(*mock, OnActorTaskAsyncChange(_, _))
        .WillByDefault(UiEventDispatcherCallback<
                       ui::UiEventDispatcher::ActorTaskAsyncChange>(
            base::BindRepeating(MakeOkResult,
                                /*requires_page_stabilization=*/true)));
  }

  ScopedExecutionEngineFactory scoped_execution_engine_factory_(
      base::BindLambdaForTesting([&](ActorTask& task) {
        CHECK(ui_event_dispatcher);
        return ExecutionEngine::CreateForTesting(
            task, std::move(ui_event_dispatcher));
      }));

  auto task_options = webui::mojom::TaskOptions::New();
  task_options->title = "Test Task";
  task_options->duration = duration;
  task_options->feature_mode = feature_mode;
  return ActorKeyedService::CreateTaskForTesting(  // IN-TEST
      std::move(task_ui_event_dispatcher), TestTaskSourceInfo(),
      &no_enterprise_policy_checker_, std::move(task_options),
      /*delegate=*/nullptr);
}

void ActorKeyedServiceFake::PauseTaskForTesting(TaskId task_id,  // IN-TEST
                                                bool from_actor) {
  GetTask(task_id)->Pause(from_actor);
  // This fake mocks out the event dispatcher, so we need to manually notify the
  // ui state manager.
  GetActorUiStateManager()->OnUiEvent(ui::TaskStateChanged(
      task_id, from_actor ? ActorTask::State::kPausedByActor
                          : ActorTask::State::kPausedByUser));
}

void ActorKeyedServiceFake::StopTaskForTesting(  // IN-TEST
    TaskId task_id,
    ActorTask::StoppedReason stopped_reason) {
  const auto duration = GetTask(task_id)->get_task_duration();
  const auto feature_mode = GetTask(task_id)->feature_mode();
  StopTask(task_id, stopped_reason);
  // This fake mocks out the event dispatcher, so we need to manually notify the
  // ui state manager.
  GetActorUiStateManager()->OnUiEvent(ui::StopTask(
      task_id, ActorTask::GetTaskStateFromStoppedReason(stopped_reason),
      "Test Task",
      /*last_acted_on_tab_handle=*/tabs::TabHandle(), duration, feature_mode));
}

}  // namespace actor
