// Copyright 2017 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/sessionmgr/agent_runner/agent_context_impl.h"

#include <memory>

#include <fuchsia/modular/cpp/fidl.h>
#include <lib/fxl/functional/make_copyable.h>

#include "peridot/bin/sessionmgr/agent_runner/agent_runner.h"
#include "peridot/lib/common/teardown.h"

namespace modular {

constexpr char kAppStoragePath[] = "/data/APP_DATA";

namespace {

// A stopgap solution to map an agent's url to a directory name where the
// agent's /data is mapped. We need three properties here - (1) two module urls
// that are the same get mapped to the same hash, (2) two modules urls that are
// different don't get the same name (with very high probability) and (3) the
// name is visually inspectable.
std::string HashAgentUrl(const std::string& agent_url) {
  std::size_t found = agent_url.find_last_of('/');
  auto last_part =
      found == agent_url.length() - 1 ? "" : agent_url.substr(found + 1);
  return std::to_string(std::hash<std::string>{}(agent_url)) + last_part;
}

};  // namespace

class AgentContextImpl::InitializeCall : public Operation<> {
 public:
  InitializeCall(AgentContextImpl* const agent_context_impl,
                 fuchsia::sys::Launcher* const launcher,
                 fuchsia::modular::AppConfig agent_config)
      : Operation("AgentContextImpl::InitializeCall", [] {},
                  agent_context_impl->url_),
        agent_context_impl_(agent_context_impl),
        launcher_(launcher),
        agent_config_(std::move(agent_config)) {}

 private:
  void Run() override {
    FXL_CHECK(agent_context_impl_->state_ == State::INITIALIZING);

    FlowToken flow{this};

    // No user intelligence provider is available during testing. We want to
    // keep going without it.
    if (!agent_context_impl_->user_intelligence_provider_) {
      auto service_list = fuchsia::sys::ServiceList::New();
      Continue(std::move(service_list), flow);
      return;
    }

    agent_context_impl_->user_intelligence_provider_->GetServicesForAgent(
        agent_context_impl_->url_,
        [this, flow](fuchsia::sys::ServiceList maxwell_service_list) {
          auto service_list = fuchsia::sys::ServiceList::New();
          service_list->names = std::move(maxwell_service_list.names);
          agent_context_impl_->service_provider_impl_.SetDefaultServiceProvider(
              maxwell_service_list.provider.Bind());
          Continue(std::move(service_list), flow);
        });
  }

  void Continue(fuchsia::sys::ServiceListPtr service_list, FlowToken flow) {
    service_list->names.push_back(fuchsia::modular::ComponentContext::Name_);
    service_list->names.push_back(fuchsia::modular::AgentContext::Name_);
    agent_context_impl_->service_provider_impl_.AddBinding(
        service_list->provider.NewRequest());
    agent_context_impl_->app_client_ =
        std::make_unique<AppClient<fuchsia::modular::Lifecycle>>(
            launcher_, std::move(agent_config_),
            std::string(kAppStoragePath) +
                HashAgentUrl(agent_context_impl_->url_),
            std::move(service_list));

    agent_context_impl_->app_client_->services().ConnectToService(
        agent_context_impl_->agent_.NewRequest());

    // We only want to use fuchsia::modular::Lifecycle if it exists.
    agent_context_impl_->app_client_->primary_service().set_error_handler(
        [agent_context_impl = agent_context_impl_](zx_status_t status) {
          agent_context_impl->app_client_->primary_service().Unbind();
        });

    // When the agent process dies, we remove it.
    // TODO(alhaad): In the future we would want to detect a crashing agent and
    // stop scheduling tasks for it.
    agent_context_impl_->app_client_->SetAppErrorHandler(
        [agent_context_impl = agent_context_impl_] {
          agent_context_impl->agent_runner_->RemoveAgent(
              agent_context_impl->url_);
        });

    // When all the |fuchsia::modular::AgentController| bindings go away maybe
    // stop the agent.
    agent_context_impl_->agent_controller_bindings_.set_empty_set_handler(
        [agent_context_impl = agent_context_impl_] {
          agent_context_impl->StopAgentIfIdle();
        });

    agent_context_impl_->state_ = State::RUNNING;
  }

  AgentContextImpl* const agent_context_impl_;
  fuchsia::sys::Launcher* const launcher_;
  fuchsia::modular::AppConfig agent_config_;

  FXL_DISALLOW_COPY_AND_ASSIGN(InitializeCall);
};

// If |terminating| is set to true, the agent will be torn down irrespective
// of whether there is an open-connection or running task. Returns |true| if the
// agent was stopped, false otherwise (could be because agent has pending
// tasks).
class AgentContextImpl::StopCall : public Operation<bool> {
 public:
  StopCall(const bool terminating, AgentContextImpl* const agent_context_impl,
           ResultCall result_call)
      : Operation("AgentContextImpl::StopCall", std::move(result_call),
                  agent_context_impl->url_),
        agent_context_impl_(agent_context_impl),
        terminating_(terminating) {}

 private:
  void Run() override {
    FlowToken flow{this, &stopped_};

    if (agent_context_impl_->state_ == State::TERMINATING) {
      return;
    }

    if (terminating_ ||
        (agent_context_impl_->agent_controller_bindings_.size() == 0 &&
         agent_context_impl_->incomplete_task_count_ == 0)) {
      Stop(flow);
    }
  }

  void Stop(FlowToken flow) {
    agent_context_impl_->state_ = State::TERMINATING;
    // Calling Teardown() below will branch |flow| into normal and timeout
    // paths. |flow| must go out of scope when either of the paths finishes.
    //
    // TODO(mesch): AppClient/AsyncHolder should implement this. See also
    // StoryProviderImpl::StopStoryShellCall.
    FlowTokenHolder branch{flow};
    agent_context_impl_->app_client_->Teardown(kBasicTimeout, [this, branch] {
      std::unique_ptr<FlowToken> cont = branch.Continue();
      if (cont) {
        Kill(*cont);
      }
    });
  }

  void Kill(FlowToken flow) {
    stopped_ = true;
    agent_context_impl_->agent_.Unbind();
    agent_context_impl_->agent_context_bindings_.CloseAll();
    agent_context_impl_->token_manager_bindings_.CloseAll();
  }

  bool stopped_ = false;
  AgentContextImpl* const agent_context_impl_;
  const bool terminating_;  // is the agent runner terminating?

  FXL_DISALLOW_COPY_AND_ASSIGN(StopCall);
};

AgentContextImpl::AgentContextImpl(const AgentContextInfo& info,
                                   fuchsia::modular::AppConfig agent_config)
    : url_(agent_config.url),
      agent_runner_(info.component_context_info.agent_runner),
      component_context_impl_(info.component_context_info,
                              kAgentComponentNamespace, url_, url_),
      token_manager_(info.token_manager),
      entity_provider_runner_(
          info.component_context_info.entity_provider_runner),
      user_intelligence_provider_(info.user_intelligence_provider) {
  service_provider_impl_.AddService<fuchsia::modular::ComponentContext>(
      [this](
          fidl::InterfaceRequest<fuchsia::modular::ComponentContext> request) {
        component_context_impl_.Connect(std::move(request));
      });
  service_provider_impl_.AddService<fuchsia::modular::AgentContext>(
      [this](fidl::InterfaceRequest<fuchsia::modular::AgentContext> request) {
        agent_context_bindings_.AddBinding(this, std::move(request));
      });
  operation_queue_.Add(
      new InitializeCall(this, info.launcher, std::move(agent_config)));
}

AgentContextImpl::~AgentContextImpl() = default;

void AgentContextImpl::NewAgentConnection(
    const std::string& requestor_url,
    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider>
        incoming_services_request,
    fidl::InterfaceRequest<fuchsia::modular::AgentController>
        agent_controller_request) {
  // Queue adding the connection
  operation_queue_.Add(new SyncCall(fxl::MakeCopyable(
      [this, requestor_url,
       incoming_services_request = std::move(incoming_services_request),
       agent_controller_request =
           std::move(agent_controller_request)]() mutable {
        FXL_CHECK(state_ == State::RUNNING);

        agent_->Connect(requestor_url, std::move(incoming_services_request));

        // Add a binding to the |controller|. When all the bindings go away,
        // the agent will stop.
        agent_controller_bindings_.AddBinding(
            this, std::move(agent_controller_request));
      })));
}

void AgentContextImpl::NewEntityProviderConnection(
    fidl::InterfaceRequest<fuchsia::modular::EntityProvider>
        entity_provider_request,
    fidl::InterfaceRequest<fuchsia::modular::AgentController>
        agent_controller_request) {
  operation_queue_.Add(new SyncCall(fxl::MakeCopyable(
      [this, entity_provider_request = std::move(entity_provider_request),
       agent_controller_request =
           std::move(agent_controller_request)]() mutable {
        FXL_CHECK(state_ == State::RUNNING);
        app_client_->services().ConnectToService(
            std::move(entity_provider_request));
        agent_controller_bindings_.AddBinding(
            this, std::move(agent_controller_request));
      })));
}

void AgentContextImpl::NewTask(const std::string& task_id) {
  operation_queue_.Add(new SyncCall([this, task_id] {
    FXL_CHECK(state_ == State::RUNNING);
    // Increment the counter for number of incomplete tasks. Decrement it when
    // we receive its callback;
    incomplete_task_count_++;
    agent_->RunTask(task_id, [this] {
      incomplete_task_count_--;
      StopAgentIfIdle();
    });
  }));
}

void AgentContextImpl::GetComponentContext(
    fidl::InterfaceRequest<fuchsia::modular::ComponentContext> request) {
  component_context_impl_.Connect(std::move(request));
}

void AgentContextImpl::GetTokenManager(
    fidl::InterfaceRequest<fuchsia::auth::TokenManager> request) {
  token_manager_bindings_.AddBinding(this, std::move(request));
}

void AgentContextImpl::GetEntityReferenceFactory(
    fidl::InterfaceRequest<fuchsia::modular::EntityReferenceFactory> request) {
  entity_provider_runner_->ConnectEntityReferenceFactory(url_,
                                                         std::move(request));
}

void AgentContextImpl::ScheduleTask(fuchsia::modular::TaskInfo task_info) {
  agent_runner_->ScheduleTask(url_, std::move(task_info));
}

void AgentContextImpl::DeleteTask(std::string task_id) {
  agent_runner_->DeleteTask(url_, task_id);
}

void AgentContextImpl::Authorize(
    fuchsia::auth::AppConfig app_config,
    fidl::InterfaceHandle<fuchsia::auth::AuthenticationUIContext>
        auth_ui_context,
    std::vector<::std::string> app_scopes, fidl::StringPtr user_profile_id,
    fidl::StringPtr auth_code, AuthorizeCallback callback) {
  FXL_LOG(ERROR) << "AgentContextImpl::Authorize() not supported from agent "
                 << "context";
  callback(fuchsia::auth::Status::INVALID_REQUEST, nullptr);
}

void AgentContextImpl::GetAccessToken(fuchsia::auth::AppConfig app_config,
                                      std::string user_profile_id,
                                      std::vector<::std::string> app_scopes,
                                      GetAccessTokenCallback callback) {
  FXL_CHECK(token_manager_);

  FXL_DLOG(INFO) << "AgentContextImpl::GetAccessToken() invoked for user:"
                 << user_profile_id;
  token_manager_->GetAccessToken(std::move(app_config),
                                 std::move(user_profile_id),
                                 std::move(app_scopes), std::move(callback));
}

void AgentContextImpl::GetIdToken(fuchsia::auth::AppConfig app_config,
                                  std::string user_profile_id,
                                  fidl::StringPtr audience,
                                  GetIdTokenCallback callback) {
  FXL_CHECK(token_manager_);

  FXL_DLOG(INFO) << "AgentContextImpl::GetIdToken() invoked for user:"
                 << user_profile_id;
  token_manager_->GetIdToken(std::move(app_config), std::move(user_profile_id),
                             std::move(audience), std::move(callback));
}

void AgentContextImpl::GetFirebaseToken(fuchsia::auth::AppConfig app_config,
                                        std::string user_profile_id,
                                        std::string audience,
                                        std::string firebase_api_key,
                                        GetFirebaseTokenCallback callback) {
  FXL_CHECK(token_manager_);

  FXL_DLOG(INFO) << "AgentContextImpl::GetFirebaseToken() invoked for user:"
                 << user_profile_id;
  token_manager_->GetFirebaseToken(
      std::move(app_config), std::move(user_profile_id), std::move(audience),
      std::move(firebase_api_key), std::move(callback));
}

void AgentContextImpl::DeleteAllTokens(fuchsia::auth::AppConfig app_config,
                                       std::string user_profile_id,
                                       DeleteAllTokensCallback callback) {
  FXL_LOG(ERROR) << "AgentContextImpl::DeleteAllTokens() not supported from "
                 << "agent context";
  callback(fuchsia::auth::Status::INVALID_REQUEST);
}

void AgentContextImpl::ListProfileIds(fuchsia::auth::AppConfig app_config,
                                      ListProfileIdsCallback callback) {
  FXL_CHECK(token_manager_);

  token_manager_->ListProfileIds(std::move(app_config), std::move(callback));
}

void AgentContextImpl::StopAgentIfIdle() {
  operation_queue_.Add(new StopCall(false /* is agent runner terminating? */,
                                    this, [this](bool stopped) {
                                      if (stopped) {
                                        agent_runner_->RemoveAgent(url_);
                                        // |this| is no longer valid at this
                                        // point.
                                      }
                                    }));
}

void AgentContextImpl::StopForTeardown(const std::function<void()>& callback) {
  FXL_DLOG(INFO) << "AgentContextImpl::StopForTeardown() " << url_;
  operation_queue_.Add(new StopCall(true /* is agent runner terminating? */,
                                    this, [this, callback](bool stopped) {
                                      FXL_DCHECK(stopped);
                                      agent_runner_->RemoveAgent(url_);
                                      callback();
                                      // |this| is no longer valid at this
                                      // point.
                                    }));
}

}  // namespace modular
