// 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/android/webapk/webapk_restore_manager.h"

#include "base/barrier_closure.h"
#include "base/strings/utf_string_conversions.h"
#include "base/types/pass_key.h"
#include "chrome/browser/android/webapk/webapk_restore_web_contents_manager.h"
#include "components/webapps/browser/web_contents/web_app_url_loader.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"

namespace webapk {

WebApkRestoreManager::WebApkRestoreManager(
    WebApkInstallService* web_apk_install_service,
    std::unique_ptr<WebApkRestoreWebContentsManager> web_contents_manager)
    : web_apk_install_service_(web_apk_install_service),
      web_contents_manager_(std::move(web_contents_manager)),
      sequenced_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}

WebApkRestoreManager::~WebApkRestoreManager() = default;

// static
WebApkRestoreManager::PassKey WebApkRestoreManager::PassKeyForTesting() {
  return PassKey();
}

void WebApkRestoreManager::PrepareRestorableApps(
    std::vector<WebApkRestoreData>&& restore_apps_list,
    RestorableAppsCallback apps_info_callback) {
  if (restore_apps_list.empty()) {
    OnAllIconsDownloaded(std::move(apps_info_callback));
    return;
  }

  for (auto&& restore_data : restore_apps_list) {
    restorable_tasks_.emplace(
        restore_data.app_id,
        CreateNewTask(std::move(restore_data.shortcut_info)));
  }

  // Prepare a web_contents and load |kAboutBlankURL| in the web contents to
  // download icons.
  web_contents_manager()->EnsureWebContentsCreated(PassKey());
  web_contents_manager()->LoadUrl(
      GURL(url::kAboutBlankURL),
      base::BindOnce(&WebApkRestoreManager::DownloadIcon,
                     weak_factory_.GetWeakPtr(),
                     std::move(apps_info_callback)));
}

void WebApkRestoreManager::DownloadIcon(
    RestorableAppsCallback apps_info_callback,
    webapps::WebAppUrlLoaderResult result) {
  auto barrier_closure = base::BarrierClosure(
      restorable_tasks_.size(),
      base::BindOnce(&WebApkRestoreManager::OnAllIconsDownloaded,
                     weak_factory_.GetWeakPtr(),
                     std::move(apps_info_callback)));

  for (auto&& [app_id, task] : restorable_tasks_) {
    task->DownloadIcon(barrier_closure);
  }
}

void WebApkRestoreManager::OnAllIconsDownloaded(
    RestorableAppsCallback apps_info_callback) {
  std::vector<std::string> app_ids;
  std::vector<std::u16string> names;
  std::vector<SkBitmap> icons;

  for (auto&& [app_id, task] : restorable_tasks_) {
    app_ids.emplace_back(app_id);
    names.emplace_back(task->app_name());
    icons.push_back(task->app_icon());
  }
  std::move(apps_info_callback).Run(app_ids, names, icons);
}

void WebApkRestoreManager::ScheduleRestoreTasks(
    const std::vector<webapps::AppId>& app_ids_to_restore) {
  for (auto app_id : app_ids_to_restore) {
    tasks_.push_back(app_id);
  }

  MaybeStartNextTask();
}

std::unique_ptr<WebApkRestoreTask> WebApkRestoreManager::CreateNewTask(
    std::unique_ptr<webapps::ShortcutInfo> restore_info) {
  return std::make_unique<WebApkRestoreTask>(
      PassKey(), web_apk_install_service_, web_contents_manager(),
      std::move(restore_info));
}

void WebApkRestoreManager::MaybeStartNextTask() {
  if (is_running_) {
    return;
  }

  if (tasks_.empty()) {
    ResetIfNotRunning();
    return;
  }

  is_running_ = true;
  web_contents_manager()->EnsureWebContentsCreated(PassKey());
  restorable_tasks_.at(tasks_.front())
      ->Start(base::BindOnce(&WebApkRestoreManager::OnTaskFinished,
                             weak_factory_.GetWeakPtr()));
}

void WebApkRestoreManager::OnTaskFinished(const GURL& manifest_id,
                                          webapps::WebApkInstallResult result) {
  tasks_.pop_front();
  is_running_ = false;

  sequenced_task_runner_->PostTask(
      FROM_HERE, base::BindOnce(&WebApkRestoreManager::MaybeStartNextTask,
                                weak_factory_.GetWeakPtr()));
}

void WebApkRestoreManager::ResetIfNotRunning() {
  if (is_running_ || !tasks_.empty()) {
    return;
  }

  restorable_tasks_.clear();
  web_contents_manager()->ClearSharedWebContents();
}

base::WeakPtr<WebApkRestoreManager> WebApkRestoreManager::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

}  // namespace webapk
