// 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/acquirers/story_info/story_info.h"

#include <sstream>

#include "peridot/bin/acquirers/story_info/story_watcher_impl.h"
#include "peridot/lib/fidl/json_xdr.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

namespace maxwell {

StoryInfoAcquirer::StoryInfoAcquirer(modular::AgentHost* const agent_host)
    : visible_stories_watcher_binding_(this),
      story_provider_watcher_binding_(this),
      focus_watcher_binding_(this) {
  // Initialize fuchsia::modular::IntelligenceServices.
  fuchsia::modular::IntelligenceServicesPtr intelligence_services;
  agent_host->startup_context()->ConnectToEnvironmentService(
      intelligence_services.NewRequest());
  intelligence_services->GetContextWriter(context_writer_.NewRequest());
  intelligence_services->GetContextReader(context_reader_.NewRequest());

  // Watch for changes to what Stories are visible.
  agent_host->startup_context()->ConnectToEnvironmentService(
      visible_stories_provider_.NewRequest());
  visible_stories_provider_->Watch(
      visible_stories_watcher_binding_.NewBinding());

  // Watch for changes in Story state.
  agent_host->startup_context()->ConnectToEnvironmentService(
      story_provider_.NewRequest());
  story_provider_->GetStories(
      story_provider_watcher_binding_.NewBinding(),
      [this](std::vector<fuchsia::modular::StoryInfo> stories) {
        for (const auto& story : stories) {
          stories_.emplace(
              std::make_pair(story.id, std::make_unique<StoryWatcherImpl>(
                                           this, context_writer_.get(),
                                           story_provider_.get(), story.id)));
        }
      });

  // Watch for changes in the focused Story.
  agent_host->startup_context()->ConnectToEnvironmentService(
      focus_provider_.NewRequest());
  focus_provider_->Watch(focus_watcher_binding_.NewBinding());

  // Write initial values for visible stories.
  OnVisibleStoriesChange({});
}

StoryInfoAcquirer::~StoryInfoAcquirer() = default;

void StoryInfoAcquirer::DropStoryWatcher(const std::string& story_id) {
  stories_.erase(story_id);
}

void StoryInfoAcquirer::Connect(
    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) {
  agent_services_.AddBinding(std::move(services));
}

void StoryInfoAcquirer::RunTask(
    const fidl::StringPtr& task_id,
    const fuchsia::modular::Agent::RunTaskCallback& callback) {
  FXL_LOG(FATAL) << "Not implemented.";
}

void StoryInfoAcquirer::Terminate(const std::function<void()>& done) { done(); }

void StoryInfoAcquirer::OnFocusChange(fuchsia::modular::FocusInfoPtr info) {
  // Set all stories to *not* focused, then set the one that's focused to
  // "focused".
  for (const auto& e : stories_) {
    if (!info->focused_story_id || e.first != info->focused_story_id) {
      e.second->OnFocusChange(false);
    }
  }
  if (info->focused_story_id) {
    auto it = stories_.find(info->focused_story_id);
    if (it == stories_.end()) {
      FXL_LOG(ERROR)
          << "RACE CONDITION: I was notified that story "
          << info->focused_story_id
          << " was focused before being notified it exists in the first place.";
      return;
    }
    it->second->OnFocusChange(true);
  }
}

void StoryInfoAcquirer::OnVisibleStoriesChange(
    fidl::VectorPtr<std::string> ids) {
  // TODO(thatguy)
}

void StoryInfoAcquirer::OnChange(fuchsia::modular::StoryInfo info,
                                 fuchsia::modular::StoryState state,
                                 fuchsia::modular::StoryVisibilityState) {
  // Here we only check if a story is new, and if so create a StoryWatcherImpl.
  // We proxy all future change events to it.
  auto it = stories_.find(info.id);
  if (it == stories_.end()) {
    auto ret = stories_.emplace(std::make_pair(
        info.id,
        std::make_unique<StoryWatcherImpl>(this, context_writer_.get(),
                                           story_provider_.get(), info.id)));
    it = ret.first;
  }
  it->second->OnStoryStateChange(std::move(info), state);
}

void StoryInfoAcquirer::OnDelete(std::string story_id) {
  const std::string id = story_id;
  // TODO(thatguy)
}

}  // namespace maxwell
