// 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/lib/ledger_client/page_client.h"

#include <memory>
#include <utility>

#include <lib/fsl/vmo/strings.h>
#include <lib/fxl/functional/make_copyable.h>

#include "peridot/lib/fidl/array_to_string.h"
#include "peridot/lib/ledger_client/ledger_client.h"

namespace modular {

PageClient::PageClient(std::string context, LedgerClient* ledger_client,
                       LedgerPageId page_id, std::string prefix)
    : binding_(this),
      context_(std::move(context)),
      ledger_client_(ledger_client),
      page_id_(std::move(page_id)),
      page_(ledger_client_->GetPage(this, context_, page_id_)),
      prefix_(std::move(prefix)) {
  fuchsia::ledger::PageSnapshotPtr snapshot;
  page_->GetSnapshot(snapshot.NewRequest(), to_array(prefix_),
                     binding_.NewBinding(),
                     [this](fuchsia::ledger::Status status) {
                       if (status != fuchsia::ledger::Status::OK) {
                         FXL_LOG(ERROR) << context_ << " Page.GetSnapshot() "
                                        << fidl::ToUnderlying(status);
                       }
                     });
}

PageClient::~PageClient() {
  // We assume ledger client always outlives page client.
  ledger_client_->DropPageClient(this);
}

fuchsia::ledger::PageSnapshotPtr PageClient::NewSnapshot(
    std::function<void()> on_error) {
  fuchsia::ledger::PageSnapshotPtr ptr;
  page_->GetSnapshot(
      ptr.NewRequest(), to_array(prefix_), nullptr /* page_watcher */,
      [this, on_error = std::move(on_error)](fuchsia::ledger::Status status) {
        if (status != fuchsia::ledger::Status::OK) {
          FXL_LOG(ERROR) << context_ << " Page.GetSnapshot() "
                         << fidl::ToUnderlying(status);
          on_error();
        }
      });
  return ptr;
}

// |PageWatcher|
void PageClient::OnChange(fuchsia::ledger::PageChange page,
                          fuchsia::ledger::ResultState result_state,
                          OnChangeCallback callback) {
  for (auto& entry : page.changed_entries) {
    // Remove key prefix maybe?
    OnPageChange(to_string(entry.key), std::move(entry.value));
  }

  for (auto& key : page.deleted_keys) {
    OnPageDelete(to_string(key));
  }

  callback(nullptr);
}

void PageClient::OnPageChange(const std::string& key,
                              fuchsia::mem::BufferPtr value) {
  std::string value_string;
  if (fsl::StringFromVmo(*value, &value_string)) {
    OnPageChange(key, value_string);
  } else {
    FXL_LOG(ERROR) << "PageClient::OnChange() " << context_ << ": "
                   << "Unable to read/copy data.";
  }
}

void PageClient::OnPageChange(const std::string& /*key*/,
                              const std::string& /*value*/) {}

void PageClient::OnPageDelete(const std::string& /*key*/) {}

void PageClient::OnPageConflict(Conflict* const conflict) {
  FXL_LOG(INFO) << "PageClient::OnPageConflict() " << context_ << " "
                << to_hex_string(conflict->key) << " " << conflict->left << " "
                << conflict->right;
};

namespace {

void GetEntriesRecursive(fuchsia::ledger::PageSnapshot* const snapshot,
                         std::vector<fuchsia::ledger::Entry>* const entries,
                         std::unique_ptr<fuchsia::ledger::Token> next_token,
                         std::function<void(fuchsia::ledger::Status)> done) {
  snapshot->GetEntries(
      std::vector<uint8_t>{} /* key_start */, std::move(next_token),
      fxl::MakeCopyable([snapshot, entries, done = std::move(done)](
                            fuchsia::ledger::Status status, auto new_entries,
                            auto next_token) mutable {
        if (status != fuchsia::ledger::Status::OK &&
            status != fuchsia::ledger::Status::PARTIAL_RESULT) {
          done(status);
          return;
        }

        for (size_t i = 0; i < new_entries.size(); ++i) {
          entries->push_back(std::move(new_entries.at(i)));
        }

        if (status == fuchsia::ledger::Status::OK) {
          done(fuchsia::ledger::Status::OK);
          return;
        }

        GetEntriesRecursive(snapshot, entries, std::move(next_token),
                            std::move(done));
      }));
}

}  // namespace

void GetEntries(fuchsia::ledger::PageSnapshot* const snapshot,
                std::vector<fuchsia::ledger::Entry>* const entries,
                std::function<void(fuchsia::ledger::Status)> done) {
  GetEntriesRecursive(snapshot, entries, nullptr /* next_token */,
                      std::move(done));
}

}  // namespace modular
