// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "peridot/bin/basemgr/basemgr_impl.h"

#include <fuchsia/ui/app/cpp/fidl.h>
#include <lib/fidl/cpp/type_converter.h>
#include <lib/fsl/types/type_converters.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <src/lib/fxl/logging.h>

#include "peridot/bin/basemgr/basemgr_settings.h"
#include "peridot/bin/basemgr/session_provider.h"
#include "peridot/bin/basemgr/wait_for_minfs.h"
#include "peridot/lib/common/async_holder.h"
#include "peridot/lib/common/teardown.h"
#include "peridot/lib/fidl/app_client.h"
#include "peridot/lib/fidl/clone.h"

namespace fidl {
template <>
// fidl::TypeConverter specialization for fuchsia::modular::session::AppConfig
// TODO(MF-277) Convert all usages of fuchsia::modular::AppConfig to
// fuchsia::modular::session::AppConfig and remove this converter.
struct TypeConverter<fuchsia::modular::AppConfig,
                     fuchsia::modular::session::AppConfig> {
  // Converts fuchsia::modular::session::AppConfig to
  // fuchsia::modular::AppConfig
  static fuchsia::modular::AppConfig Convert(
      const fuchsia::modular::session::AppConfig& config) {
    fuchsia::modular::AppConfig app_config;
    app_config.url = config.url().c_str();

    if (config.has_args()) {
      app_config.args = fidl::To<fidl::VectorPtr<std::string>>(config.args());
    }

    return app_config;
  }
};
}  // namespace fidl

namespace modular {

namespace {

// TODO(MF-134): This key is duplicated in
// topaz/lib/settings/lib/device_info.dart. Remove this key once factory reset
// is provided to topaz as a service.
// The key for factory reset toggles.
constexpr char kFactoryResetKey[] = "FactoryReset";

constexpr char kTokenManagerFactoryUrl[] =
    "fuchsia-pkg://fuchsia.com/token_manager_factory#meta/"
    "token_manager_factory.cmx";

}  // namespace

BasemgrImpl::BasemgrImpl(
    fuchsia::modular::session::BasemgrConfig config,
    fuchsia::sys::Launcher* const launcher,
    fuchsia::ui::policy::PresenterPtr presenter,
    fuchsia::devicesettings::DeviceSettingsManagerPtr device_settings_manager,
    fuchsia::wlan::service::WlanPtr wlan,
    fuchsia::auth::account::AccountManagerPtr account_manager,
    fit::function<void()> on_shutdown)
    : config_(std::move(config)),
      launcher_(launcher),
      presenter_(std::move(presenter)),
      device_settings_manager_(std::move(device_settings_manager)),
      wlan_(std::move(wlan)),
      account_manager_(std::move(account_manager)),
      on_shutdown_(std::move(on_shutdown)),
      base_shell_context_binding_(this),
      authentication_context_provider_binding_(this),
      session_provider_("SessionProvider") {
  UpdateSessionShellConfig();

  Start();
}

BasemgrImpl::~BasemgrImpl() = default;

void BasemgrImpl::Connect(
    fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug> request) {
  basemgr_bindings_.AddBinding(this, std::move(request));
}

void BasemgrImpl::StartBaseShell() {
  if (base_shell_running_) {
    FXL_DLOG(INFO) << "StartBaseShell() called when already running";

    return;
  }

  auto base_shell_config =
      fidl::To<fuchsia::modular::AppConfig>(config_.base_shell().app_config());
  base_shell_app_ = std::make_unique<AppClient<fuchsia::modular::Lifecycle>>(
      launcher_, std::move(base_shell_config));

  auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();

  fuchsia::ui::app::ViewProviderPtr base_shell_view_provider;
  base_shell_app_->services().ConnectToService(
      base_shell_view_provider.NewRequest());
  base_shell_view_provider->CreateView(std::move(view_token.value), nullptr,
                                       nullptr);

  presentation_container_ = std::make_unique<PresentationContainer>(
      presenter_.get(), std::move(view_holder_token),
      /* shell_config= */ GetActiveSessionShellConfig(),
      /* on_swap_session_shell= */ [this] {
        SelectNextSessionShell(/* callback= */ [] {});
      });

  // TODO(alexmin): Remove BaseShellParams.
  fuchsia::modular::BaseShellParams params;
  base_shell_app_->services().ConnectToService(base_shell_.NewRequest());
  base_shell_->Initialize(base_shell_context_binding_.NewBinding(),
                          /* base_shell_params= */ std::move(params));

  base_shell_running_ = true;
}

FuturePtr<> BasemgrImpl::StopBaseShell() {
  if (!base_shell_running_) {
    FXL_DLOG(INFO) << "StopBaseShell() called when already stopped";

    return Future<>::CreateCompleted("StopBaseShell::Completed");
  }

  auto did_stop = Future<>::Create("StopBaseShell");

  base_shell_app_->Teardown(kBasicTimeout, [did_stop, this] {
    FXL_DLOG(INFO) << "- fuchsia::modular::BaseShell down";

    base_shell_running_ = false;
    did_stop->Complete();
  });

  return did_stop;
}

FuturePtr<> BasemgrImpl::StopTokenManagerFactoryApp() {
  if (!token_manager_factory_app_) {
    FXL_DLOG(INFO)
        << "StopTokenManagerFactoryApp() called when already stopped";

    return Future<>::CreateCompleted("StopTokenManagerFactoryApp::Completed");
  }

  auto did_stop = Future<>::Create("StopTokenManagerFactoryApp");

  token_manager_factory_app_->Teardown(kBasicTimeout, [did_stop, this] {
    FXL_DLOG(INFO) << "- fuchsia::auth::TokenManagerFactory down";

    token_manager_factory_app_.release();
    did_stop->Complete();
  });

  return did_stop;
}

void BasemgrImpl::Start() {
  if (config_.test()) {
    // Print test banner.
    FXL_LOG(INFO)
        << std::endl
        << std::endl
        << "======================== Starting Test [" << config_.test_name()
        << "]" << std::endl
        << "============================================================"
        << std::endl;
  }

  // Wait for persistent data to come up.
  if (config_.use_minfs()) {
    WaitForMinfs();
  }

  auto sessionmgr_config =
      fidl::To<fuchsia::modular::AppConfig>(config_.sessionmgr());
  auto story_shell_config =
      fidl::To<fuchsia::modular::AppConfig>(config_.story_shell().app_config());
  session_provider_.reset(new SessionProvider(
      /* delegate= */ this, launcher_, std::move(sessionmgr_config),
      CloneStruct(session_shell_config_), std::move(story_shell_config),
      config_.use_session_shell_for_story_shell_factory(),
      /* on_zero_sessions= */
      [this] {
        if (config_.base_shell().keep_alive_after_login()) {
          // TODO(MI4-1117): Integration tests currently
          // expect base shell to always be running. So, if
          // we're running under a test, DidLogin() will not
          // shut down the base shell after login; thus this
          // method doesn't need to re-start the base shell
          // after a logout.
          return;
        }

        FXL_DLOG(INFO) << "Re-starting due to logout";
        ShowSetupOrLogin();
      }));

  InitializeUserProvider();

  ReportEvent(ModularEvent::BOOTED_TO_BASEMGR);
}

void BasemgrImpl::InitializeUserProvider() {
  token_manager_factory_app_.release();
  fuchsia::modular::AppConfig token_manager_config;
  token_manager_config.url = kTokenManagerFactoryUrl;
  token_manager_factory_app_ =
      std::make_unique<AppClient<fuchsia::modular::Lifecycle>>(
          launcher_, CloneStruct(token_manager_config));
  token_manager_factory_app_->services().ConnectToService(
      token_manager_factory_.NewRequest());

  session_user_provider_impl_ = std::make_unique<SessionUserProviderImpl>(
      account_manager_.get(), token_manager_factory_.get(),
      authentication_context_provider_binding_.NewBinding().Bind(),
      /* on_initialize= */
      [this] { ShowSetupOrLogin(); },
      /* on_login= */
      [this](fuchsia::modular::auth::AccountPtr account,
             fuchsia::auth::TokenManagerPtr ledger_token_manager,
             fuchsia::auth::TokenManagerPtr agent_token_manager) {
        OnLogin(std::move(account), std::move(ledger_token_manager),
                std::move(agent_token_manager));
      });
}

void BasemgrImpl::GetUserProvider(
    fidl::InterfaceRequest<fuchsia::modular::UserProvider> request) {
  session_user_provider_impl_->Connect(std::move(request));
}

void BasemgrImpl::Shutdown() {
  // Prevent the shutdown sequence from running twice.
  if (state_ == State::SHUTTING_DOWN) {
    return;
  }

  state_ = State::SHUTTING_DOWN;

  FXL_DLOG(INFO) << "fuchsia::modular::BaseShellContext::Shutdown()";

  if (config_.test()) {
    FXL_LOG(INFO)
        << std::endl
        << "============================================================"
        << std::endl
        << "======================== [" << config_.test_name() << "] Done";
  }

  // |session_provider_| teardown is asynchronous because it holds the
  // sessionmgr processes.
  session_provider_.Teardown(kSessionProviderTimeout, [this] {
    StopBaseShell()->Then([this] {
      FXL_DLOG(INFO) << "- fuchsia::modular::BaseShell down";
      session_user_provider_impl_.reset();
      FXL_DLOG(INFO) << "- fuchsia::modular::UserProvider down";

      StopTokenManagerFactoryApp()->Then([this] {
        FXL_DLOG(INFO) << "- fuchsia::auth::TokenManagerFactory down";
        FXL_LOG(INFO) << "Clean shutdown";
        on_shutdown_();
      });
    });
  });
}

void BasemgrImpl::GetAuthenticationUIContext(
    fidl::InterfaceRequest<fuchsia::auth::AuthenticationUIContext> request) {
  // TODO(MI4-1107): Basemgr needs to implement AuthenticationUIContext
  // itself, and proxy calls for StartOverlay & StopOverlay to BaseShell,
  // starting it if it's not running yet.
  base_shell_->GetAuthenticationUIContext(std::move(request));
}

void BasemgrImpl::OnLogin(fuchsia::modular::auth::AccountPtr account,
                          fuchsia::auth::TokenManagerPtr ledger_token_manager,
                          fuchsia::auth::TokenManagerPtr agent_token_manager) {
  auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();

  auto did_start_session = session_provider_->StartSession(
      std::move(view_token), std::move(account),
      std::move(ledger_token_manager), std::move(agent_token_manager));
  if (!did_start_session) {
    FXL_LOG(WARNING) << "Session was already started and the logged in user "
                        "could not join the session.";
    return;
  }

  // TODO(MI4-1117): Integration tests currently expect base shell to always be
  // running. So, if we're running under a test, do not shut down the base shell
  // after login.
  if (!config_.base_shell().keep_alive_after_login()) {
    FXL_DLOG(INFO) << "Stopping base shell due to login";
    StopBaseShell();
  }

  // Ownership of the Presenter should be moved to the session shell for tests
  // that enable presenter, and production code.
  if (!config_.test() || config_.enable_presenter()) {
    presentation_container_ = std::make_unique<PresentationContainer>(
        presenter_.get(), std::move(view_holder_token),
        /* shell_config= */ GetActiveSessionShellConfig(),
        /* on_swap_session_shell= */ [this] {
          SelectNextSessionShell(/* callback= */ [] {});
        });
  }
}

void BasemgrImpl::SelectNextSessionShell(
    SelectNextSessionShellCallback callback) {
  if (state_ == State::SHUTTING_DOWN) {
    FXL_DLOG(INFO)
        << "SelectNextSessionShell() not supported while shutting down";
    callback();
    return;
  }

  if (config_.session_shell_map().empty()) {
    FXL_DLOG(INFO) << "No session shells has been defined";
    callback();
    return;
  }
  auto shell_count = config_.session_shell_map().size();
  if (shell_count <= 1) {
    FXL_DLOG(INFO)
        << "Only one session shell has been defined so switch is disabled";
    callback();
    return;
  }

  active_session_shell_configs_index_ =
      (active_session_shell_configs_index_ + 1) % shell_count;

  UpdateSessionShellConfig();

  session_provider_->SwapSessionShell(CloneStruct(session_shell_config_))
      ->Then([callback = std::move(callback)] {
        FXL_LOG(INFO) << "Swapped session shell";
        callback();
      });
}

fuchsia::modular::session::SessionShellConfig
BasemgrImpl::GetActiveSessionShellConfig() {
  return CloneStruct(config_.session_shell_map()
                         .at(active_session_shell_configs_index_)
                         .config());
}

void BasemgrImpl::UpdateSessionShellConfig() {
  session_shell_config_ = CloneStruct(fidl::To<fuchsia::modular::AppConfig>(
      config_.session_shell_map()
          .at(active_session_shell_configs_index_)
          .config()
          .app_config()));
}

void BasemgrImpl::ShowSetupOrLogin() {
  auto show_setup_or_login = [this] {
    // If there are no session shell settings specified, default to showing
    // setup.
    if (!config_.test() && active_session_shell_configs_index_ >=
                               config_.session_shell_map().size()) {
      StartBaseShell();
      return;
    }

    // Login as the first user, or show setup. This asssumes that:
    // 1) Basemgr has exclusive access to AccountManager.
    // 2) There are only 0 or 1 authenticated accounts ever.
    account_manager_->GetAccountIds(
        [this](
            std::vector<fuchsia::auth::account::LocalAccountId> account_ids) {
          if (account_ids.empty()) {
            StartBaseShell();
          } else {
            fuchsia::modular::UserLoginParams2 params;
            params.account_id = std::to_string(account_ids.at(0).id);
            session_user_provider_impl_->Login2(std::move(params));
          }
        });
  };

  // TODO(MF-347): Handle scenario where device settings manager channel is
  // dropped before error handler is set.
  // TODO(MF-134): Modular should not be handling factory reset.
  // If the device needs factory reset, remove all the users before proceeding
  // with setup.
  device_settings_manager_.set_error_handler(
      [show_setup_or_login](zx_status_t status) { show_setup_or_login(); });
  device_settings_manager_->GetInteger(
      kFactoryResetKey,
      [this, show_setup_or_login](int factory_reset_value,
                                  fuchsia::devicesettings::Status status) {
        if (status == fuchsia::devicesettings::Status::ok &&
            factory_reset_value > 0) {
          FXL_LOG(INFO) << "Factory reset initiated";
          // Unset the factory reset flag.
          device_settings_manager_->SetInteger(
              kFactoryResetKey, 0, [](bool result) {
                if (!result) {
                  FXL_LOG(WARNING) << "Factory reset flag was not updated.";
                }
              });

          session_user_provider_impl_->RemoveAllUsers([this] {
            wlan_->ClearSavedNetworks([this] { StartBaseShell(); });
          });
        } else {
          show_setup_or_login();
        }
      });
}

void BasemgrImpl::RestartSession(RestartSessionCallback on_restart_complete) {
  session_provider_->RestartSession(std::move(on_restart_complete));
}

void BasemgrImpl::LoginAsGuest() {
  fuchsia::modular::UserLoginParams2 params;
  session_user_provider_impl_->Login2(std::move(params));
}

void BasemgrImpl::LogoutUsers(fit::function<void()> callback) {
  session_user_provider_impl_->RemoveAllUsers(std::move(callback));
}

void BasemgrImpl::GetPresentation(
    fidl::InterfaceRequest<fuchsia::ui::policy::Presentation> request) {
  presentation_container_->GetPresentation(std::move(request));
}

}  // namespace modular
