// 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 <fuchsia/modular/cpp/fidl.h>
#include <lib/app_driver/cpp/module_driver.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/component/cpp/connect.h>
#include <lib/message_queue/cpp/message_sender_client.h>
#include <test/peridot/tests/trigger/cpp/fidl.h>

#include "peridot/public/lib/integration_testing/cpp/reporting.h"
#include "peridot/public/lib/integration_testing/cpp/testing.h"
#include "peridot/tests/trigger/defs.h"

using ::modular::testing::Await;
using ::modular::testing::Signal;
using ::modular::testing::TestPoint;
using ::test::peridot::tests::trigger::TriggerTestServicePtr;

namespace {

// Cf. README.md for what this test does and how.
class TestModule {
 public:
  TestPoint initialized_{"Root module initialized"};

  TestModule(modular::ModuleHost* const module_host,
             fidl::InterfaceRequest<
                 fuchsia::ui::app::ViewProvider> /*view_provider_request*/) {
    modular::testing::Init(module_host->startup_context(), __FILE__);
    initialized_.Pass();

    // Exercise fuchsia::modular::ComponentContext.ConnectToAgent()
    module_host->module_context()->GetComponentContext(
        component_context_.NewRequest());

    fuchsia::sys::ServiceProviderPtr agent_services;
    component_context_->ConnectToAgent(kTestAgent, agent_services.NewRequest(),
                                       agent_controller_.NewRequest());
    component::ConnectToService(agent_services.get(),
                                agent_service_.NewRequest());

    // The message queue that is used to verify deletion triggers from explicit
    // deletes.
    component_context_->ObtainMessageQueue("explicit_test",
                                           explicit_msg_queue_.NewRequest());
    // The message queue that is used to verify deletion triggers from deletes
    // when the module's namespace is torn down. The test session shell will
    // verify that the agent is notified of this queues deletion.
    component_context_->ObtainMessageQueue("implicit_test",
                                           implicit_msg_queue_.NewRequest());
    implicit_msg_queue_->GetToken([this](fidl::StringPtr token) {
      modular::testing::GetStore()->Put("trigger_test_module_queue_token",
                                        token, [] {});
      agent_service_->ObserveMessageQueueDeletion(token);
      explicit_msg_queue_->GetToken([this](fidl::StringPtr token) {
        explicit_queue_token_ = token;
        agent_service_->ObserveMessageQueueDeletion(std::move(token));

        TestMessageQueueMessageTrigger();
      });
    });
  }

  TestPoint received_trigger_token_{"Received trigger token"};
  TestPoint agent_connected_{"fuchsia::modular::Agent accepted connection"};
  TestPoint agent_stopped_{"fuchsia::modular::Agent stopped"};
  TestPoint task_triggered_{"fuchsia::modular::Agent task triggered"};
  void TestMessageQueueMessageTrigger() {
    Await("trigger_test_agent_connected", [this] {
      agent_connected_.Pass();
      agent_service_->GetMessageQueueToken([this](fidl::StringPtr token) {
        received_trigger_token_.Pass();

        // Stop the agent.
        agent_controller_.Unbind();

        Await("trigger_test_agent_stopped", [this, token] {
          agent_stopped_.Pass();

          // Send a message to the stopped agent which should
          // trigger it.
          component_context_->GetMessageSender(token,
                                               message_sender_.NewRequest());
          message_sender_.Send("Time to wake up...");

          Await("message_queue_message", [this] {
            task_triggered_.Pass();
            Await("trigger_test_agent_stopped",
                  [this] { TestMessageQueueDeletionTrigger(); });
          });
        });
      });
    });
  }

  TestPoint queue_deleted_{"Message queue deletion task triggered."};
  void TestMessageQueueDeletionTrigger() {
    fuchsia::sys::ServiceProviderPtr agent_services;
    component_context_->ConnectToAgent(kTestAgent, agent_services.NewRequest(),
                                       agent_controller_.NewRequest());
    component::ConnectToService(agent_services.get(),
                                agent_service_.NewRequest());

    // First wait for the agent to connect, and then kill it.
    Await("trigger_test_agent_connected", [this] {
      Await("trigger_test_agent_token_received", [this] {
        agent_controller_.Unbind();
        Await("trigger_test_agent_stopped", [this] {
          // When the agent has stopped, delete the message queue and verify
          // that the agent is woken up and notified.
          component_context_->DeleteMessageQueue("explicit_test");
          Await(explicit_queue_token_, [this] {
            queue_deleted_.Pass();
            Signal("trigger_test_module_done");
          });
        });
      });
    });
  }

  TestPoint stopped_{"Root module stopped"};
  // Called by ModuleDriver.
  void Terminate(fit::function<void()> done) {
    stopped_.Pass();
    modular::testing::Done(std::move(done));
  }

 private:
  fuchsia::modular::AgentControllerPtr agent_controller_;
  TriggerTestServicePtr agent_service_;
  fuchsia::modular::ComponentContextPtr component_context_;
  // The queue used for observing explicit queue deletion.
  fuchsia::modular::MessageQueuePtr explicit_msg_queue_;
  std::string explicit_queue_token_;
  // The queue used for observing queue deletion when module's namespace is torn
  // down.
  fuchsia::modular::MessageQueuePtr implicit_msg_queue_;
  modular::MessageSenderClient message_sender_;

  FXL_DISALLOW_COPY_AND_ASSIGN(TestModule);
};

}  // namespace

int main(int /*argc*/, const char** /*argv*/) {
  async::Loop loop(&kAsyncLoopConfigAttachToThread);
  auto context = component::StartupContext::CreateFromStartupInfo();
  modular::ModuleDriver<TestModule> driver(context.get(),
                                           [&loop] { loop.Quit(); });
  loop.Run();
  return 0;
}
