// Copyright 2021 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/ash/app_mode/kiosk_system_session.h"

#include <memory>
#include <optional>
#include <string>

#include "ash/accessibility/accessibility_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "base/check.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/notimplemented.h"
#include "chrome/browser/ash/app_mode/app_launch_utils.h"
#include "chrome/browser/ash/app_mode/auto_sleep/device_weekly_scheduled_suspend_controller.h"
#include "chrome/browser/ash/app_mode/kiosk_app_types.h"
#include "chrome/browser/ash/app_mode/kiosk_app_update_service.h"
#include "chrome/browser/ash/app_mode/kiosk_app_update_service_factory.h"
#include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h"
#include "chrome/browser/ash/app_mode/kiosk_mode_idle_app_name_notification.h"
#include "chrome/browser/ash/app_mode/metrics/network_connectivity_metrics_service.h"
#include "chrome/browser/ash/app_mode/metrics/periodic_metrics_service.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h"
#include "chromeos/ash/components/install_attributes/install_attributes.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user.h"
#include "content/public/browser/web_contents.h"

namespace ash {

namespace {

// Start the floating accessibility menu in ash-chrome if the
// `FloatingAccessibilityMenuEnabled` policy is enabled.
void StartFloatingAccessibilityMenu() {
  auto* accessibility_controller = AccessibilityController::Get();
  if (accessibility_controller) {
    accessibility_controller->ShowFloatingMenuIfEnabled();
  }
}

}  // namespace

KioskSystemSession::KioskSystemSession(
    PrefService& local_state,
    Profile* profile,
    const KioskAppId& kiosk_app_id,
    const std::optional<webapps::AppId>& app_id)
    : local_state_(local_state),
      profile_(profile),
      browser_session_(profile),
      kiosk_app_id_(kiosk_app_id),
      network_metrics_service_(
          std::make_unique<NetworkConnectivityMetricsService>(local_state)),
      periodic_metrics_service_(std::make_unique<PeriodicMetricsService>()),
      low_disk_metrics_service_(local_state),
      network_state_observer_(profile->GetPrefs()) {
  switch (kiosk_app_id_.type) {
    case KioskAppType::kChromeApp:
      InitForChromeAppKiosk();
      break;
    case KioskAppType::kWebApp:
      CHECK(app_id.has_value());
      InitForWebKiosk(*app_id);
      break;
    case KioskAppType::kIsolatedWebApp:
      CHECK(app_id.has_value());
      InitForIwaKiosk(*app_id);
      break;
    case KioskAppType::kArcvmApp:
      // TODO(crbug.com/418950414): Implement kiosk system session for ARCVM
      // kiosk. Decide if KioskBrowserSession and metrics are needed.
      NOTIMPLEMENTED() << "No KioskSystemSession init for Arcvm kiosk";
  }
}

KioskSystemSession::~KioskSystemSession() = default;

void KioskSystemSession::InitForChromeAppKiosk() {
  const std::string& app_id = kiosk_app_id_.app_id.value();
  browser_session_.InitForChromeAppKiosk(app_id);
  InitKioskAppUpdateService(app_id);
  SetRebootAfterUpdateIfNecessary();
  InitCommon();
}

void KioskSystemSession::InitForWebKiosk(const webapps::AppId& app_id) {
  browser_session_.InitForWebKiosk(app_id);
  InitCommon();
}

void KioskSystemSession::InitForIwaKiosk(const webapps::AppId& app_id) {
  browser_session_.InitForIwaKiosk(app_id);
  InitCommon();
}

void KioskSystemSession::InitCommon() {
  StartFloatingAccessibilityMenu();
  periodic_metrics_service_->StartRecordingPeriodicMetrics();
}

void KioskSystemSession::ShuttingDown() {
  network_metrics_service_.reset();
}

void KioskSystemSession::InitKioskAppUpdateService(const std::string& app_id) {
  // Set the app_id for the current instance of KioskAppUpdateService.
  auto* update_service = KioskAppUpdateServiceFactory::GetForProfile(profile());
  DCHECK(update_service);
  if (update_service) {
    update_service->Init(app_id);
  }

  // Start to monitor external update from usb stick.
  KioskChromeAppManager::Get()->MonitorKioskExternalUpdate();
}

void KioskSystemSession::SetRebootAfterUpdateIfNecessary() {
  if (!ash::InstallAttributes::Get()->IsEnterpriseManaged()) {
    local_state_->SetBoolean(ash::prefs::kRebootAfterUpdate, true);
    KioskModeIdleAppNameNotification::Initialize();
  }
}

void KioskSystemSession::OnGuestAdded(
    content::WebContents* guest_web_contents) {
  browser_session_.OnGuestAdded(guest_web_contents);
}

void KioskSystemSession::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterBooleanPref(
      ash::prefs::kKioskActiveWiFiCredentialsScopeChangeEnabled, false);
}

Profile* KioskSystemSession::profile() const {
  CHECK(profile_);
  return profile_;
}

bool KioskSystemSession::is_shutting_down() const {
  return browser_session_.is_shutting_down();
}

BrowserDelegate* KioskSystemSession::GetSettingsBrowserForTesting() {
  return browser_session_.GetSettingsBrowserForTesting();  // IN-TEST
}

void KioskSystemSession::SetOnHandleBrowserCallbackForTesting(
    base::RepeatingCallback<void(bool)> callback) {
  browser_session_.SetOnHandleBrowserCallbackForTesting(callback);  // IN-TEST
}

}  // namespace ash
