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

#include <lib/context/cpp/context_metadata_builder.h>
#include <lib/context/cpp/formatting.h>
#include <lib/fidl/cpp/optional.h>
#include <lib/fxl/functional/make_copyable.h>

#include "peridot/bin/acquirers/story_info/link_watcher_impl.h"
#include "peridot/bin/acquirers/story_info/story_info.h"
#include "peridot/bin/sessionmgr/storage/constants_and_utils.h"  // MakeLinkKey, EncodeModulePath

namespace maxwell {

StoryWatcherImpl::StoryWatcherImpl(
    StoryInfoAcquirer* const owner,
    fuchsia::modular::ContextWriter* const writer,
    fuchsia::modular::StoryProvider* const story_provider,
    const std::string& story_id)
    : owner_(owner),
      writer_(writer),
      story_id_(story_id),
      story_watcher_binding_(this),
      story_links_watcher_binding_(this) {
  story_provider->GetController(story_id, story_controller_.NewRequest());

  story_controller_.set_error_handler(
      [this](zx_status_t status) { owner_->DropStoryWatcher(story_id_); });

  story_controller_->Watch(story_watcher_binding_.NewBinding());

  story_watcher_binding_.set_error_handler(
      [this](zx_status_t status) { owner_->DropStoryWatcher(story_id_); });

  context_metadata_ = ContextMetadataBuilder()
                          .SetStoryId(story_id)
                          .SetStoryFocused(false)
                          .Build();
  // TODO(thatguy): Add StoryState.
  // TODO(thatguy): Add visible state.

  writer_->CreateValue(context_value_.NewRequest(),
                       fuchsia::modular::ContextValueType::STORY);
  fuchsia::modular::ContextMetadata metadata;
  fidl::Clone(context_metadata_, &metadata);
  context_value_->Set(nullptr /* content */,
                      fidl::MakeOptional(std::move(metadata)));

  story_controller_->GetActiveLinks(
      story_links_watcher_binding_.NewBinding(),
      [this](std::vector<fuchsia::modular::LinkPath> links) mutable {
        for (fuchsia::modular::LinkPath& link_path : links) {
          WatchLink(std::move(link_path));
        }
      });
}

StoryWatcherImpl::~StoryWatcherImpl() = default;

void StoryWatcherImpl::OnStateChange(fuchsia::modular::StoryState new_state) {
  // TODO(thatguy): Add recording of state to fuchsia::modular::StoryMetadata.
}

void StoryWatcherImpl::OnModuleAdded(fuchsia::modular::ModuleData module_data) {
  ContextModuleMetadata data;
  context_value_->CreateChildValue(data.value_writer.NewRequest(),
                                   fuchsia::modular::ContextValueType::MODULE);
  auto metadata = ContextMetadataBuilder()
                      .SetModuleUrl(module_data.module_url)
                      .SetModulePath(module_data.module_path)
                      .Build();
  fidl::Clone(metadata, &data.metadata);
  data.value_writer->Set(nullptr /* content */,
                         fidl::MakeOptional(std::move(metadata)));
  auto path = modular::EncodeModulePath(module_data.module_path);
  module_values_.emplace(path, std::move(data));
}

void StoryWatcherImpl::OnModuleFocused(
    std::vector<std::string> module_path) {
  auto key = modular::EncodeModulePath(module_path);
  auto it = module_values_.find(key);
  if (it == module_values_.end()) {
    return;
  }
  if (!last_module_focus_key_.empty()) {
    auto it_last = module_values_.find(last_module_focus_key_);
    if (it_last != module_values_.end()) {
      UpdateModuleFocus(&it_last->second, false);
    }
  }
  UpdateModuleFocus(&it->second, true);
  last_module_focus_key_ = key;
}

void StoryWatcherImpl::OnNewLink(fuchsia::modular::LinkPath link_path) {
  WatchLink(std::move(link_path));
}

void StoryWatcherImpl::WatchLink(fuchsia::modular::LinkPath link_path) {
  links_.emplace(std::make_pair(
      modular::MakeLinkKey(link_path),
      std::make_unique<LinkWatcherImpl>(this, story_controller_.get(),
                                        story_id_, context_value_.get(),
                                        std::move(link_path))));
}

void StoryWatcherImpl::OnFocusChange(bool focused) {
  context_metadata_ = ContextMetadataBuilder(std::move(context_metadata_))
                          .SetStoryFocused(focused)
                          .Build();
  fuchsia::modular::ContextMetadata metadata;
  fidl::Clone(context_metadata_, &metadata);
  context_value_->Set(nullptr /* content */,
                      fidl::MakeOptional(std::move(metadata)));
}

void StoryWatcherImpl::OnStoryStateChange(fuchsia::modular::StoryInfo info,
                                          fuchsia::modular::StoryState state) {
  // TODO(thatguy): Record this state too.
}

void StoryWatcherImpl::DropLink(const std::string& link_key) {
  links_.erase(link_key);
}

void StoryWatcherImpl::UpdateModuleFocus(ContextModuleMetadata* data,
                                         bool focused) {
  auto metadata = ContextMetadataBuilder(std::move(data->metadata))
                      .SetModuleFocused(focused)
                      .Build();
  fidl::Clone(metadata, &data->metadata);
  data->value_writer->Set(nullptr /* content */,
                          fidl::MakeOptional(std::move(metadata)));
}

}  // namespace maxwell
