// Copyright 2022 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/chromeos/extensions/login_screen/login/cleanup/browser_cleanup_handler.h"

#include <thread>
#include <utility>

#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
#include "chrome/browser/lifetime/application_lifetime_desktop.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/browser_window/public/profile_browser_collection.h"
#include "content/public/browser/browsing_data_remover.h"

namespace {

// TODO(maleksandrov, b:258196743) Move the logic into BrowserList class.
bool HasBrowsersForProfile(Profile* profile) {
  bool found = false;
  ForEachCurrentBrowserWindowInterfaceOrderedByActivation(
      [profile, &found](BrowserWindowInterface* browser_window_interface) {
        if (browser_window_interface->GetProfile()->GetOriginalProfile() ==
            profile->GetOriginalProfile()) {
          found = true;
          return false;
        }
        return true;
      });
  return found;
}

}  // namespace

namespace chromeos {

BrowserCleanupHandler::BrowserCleanupHandler() = default;

BrowserCleanupHandler::~BrowserCleanupHandler() = default;

void BrowserCleanupHandler::Cleanup(CleanupHandlerCallback callback) {
  DCHECK(callback_.is_null());

  profile_ = ProfileManager::GetActiveUserProfile();
  if (!profile_) {
    std::move(callback).Run("There is no active user");
    return;
  }

  callback_ = std::move(callback);

  if (!HasBrowsersForProfile(profile_)) {
    RemoveBrowserHistory();
    return;
  }

  browser_collection_observation_.Observe(
      GlobalBrowserCollection::GetInstance());

  // `on_close_success` doesn't wait for browser to close and is therefore not
  // used. `on_close_aborted` cannot be reached because `skip_beforeunload` is
  // true. Instead, this process should trigger `OnBrowserRemoved` method.
  chrome::CloseAllBrowsersWithProfile(profile_, /*skip_beforeunload=*/true);
}

void BrowserCleanupHandler::OnBrowserClosed(BrowserWindowInterface* browser) {
  if (browser->GetProfile() != profile_) {
    return;
  }

  // In case any browser window is still open for current profile the cleanup
  // must not proceed otherwise some open tabs can remain in browser data.
  if (HasBrowsersForProfile(profile_)) {
    return;
  }

  browser_collection_observation_.Reset();
  RemoveBrowserHistory();
}

void BrowserCleanupHandler::RemoveBrowserHistory() {
  data_remover_ = profile_->GetBrowsingDataRemover();
  data_remover_->AddObserver(this);

  // This process should trigger `OnBrowsingDataRemoverDone` method.
  data_remover_->RemoveAndReply(
      /*delete_begin=*/base::Time(),
      /*delete_end=*/base::Time::Max(),
      /*remove_mask=*/chrome_browsing_data_remover::ALL_DATA_TYPES,
      /*origin_type_mask=*/
      content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB |
          content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
      /*observer=*/this);
}

void BrowserCleanupHandler::OnBrowsingDataRemoverDone(
    uint64_t failed_data_types) {
  data_remover_->RemoveObserver(this);

  if (failed_data_types == 0) {
    std::move(callback_).Run(std::nullopt);
    return;
  }

  std::move(callback_).Run("Failed to cleanup all data with flag: " +
                           base::NumberToString(failed_data_types));
}

}  // namespace chromeos
