// Copyright 2020 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 "src/storage/volume_image/volume_descriptor.h"

#include <algorithm>
#include <array>
#include <cstdlib>
#include <sstream>
#include <string_view>
#include <vector>

#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "rapidjson/error/error.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "src/storage/volume_image/options.h"
#include "src/storage/volume_image/utils/guid.h"

namespace storage::volume_image {

fit::result<VolumeDescriptor, std::string> VolumeDescriptor::Deserialize(
    fbl::Span<const uint8_t> serialized) {
  rapidjson::Document document;
  rapidjson::ParseResult result =
      document.Parse(reinterpret_cast<const char*>(serialized.data()), serialized.size());

  if (result.IsError()) {
    std::ostringstream error;
    error << "Error parsing serialized VolumeDescriptor. "
          << rapidjson::GetParseError_En(result.Code()) << std::endl;
    return fit::error(error.str());
  }

  uint64_t magic = document["magic"].GetUint64();
  if (magic != kMagic) {
    return fit::error("Invalid Magic\n");
  }

  VolumeDescriptor descriptor = {};
  const std::string& instance_guid = document["instance_guid"].GetString();
  // The stringified version includes 4 Hyphens.
  if (instance_guid.length() != kGuidStrLength) {
    return fit::error("instance_guid length must be 36 bytes.\n");
  }
  auto instance_bytes = Guid::FromString(instance_guid);
  if (instance_bytes.is_error()) {
    return instance_bytes.take_error_result();
  }
  descriptor.instance = instance_bytes.take_value();

  const std::string& type_guid = document["type_guid"].GetString();
  // The stringified version includes 4 Hyphens.
  if (type_guid.length() != kGuidStrLength) {
    return fit::error("type_guid length must be 36 bytes.\n");
  }

  auto type_bytes = Guid::FromString(type_guid);
  if (type_bytes.is_error()) {
    return type_bytes.take_error_result();
  }
  descriptor.type = type_bytes.take_value();

  const std::string& name = document["name"].GetString();
  if (name.length() > kNameLength) {
    return fit::error("name exceeds maximum length.\n");
  }
  descriptor.name = name;

  descriptor.block_size = document["block_size"].GetUint64();

  auto encryption_enum = StringAsEnum<EncryptionType>(document["encryption_type"].GetString());
  if (encryption_enum.is_error()) {
    return encryption_enum.take_error_result();
  }
  descriptor.encryption = encryption_enum.take_value();

  if (document.HasMember("options")) {
    const auto& option_set = document["options"].GetArray();
    for (auto& option : option_set) {
      auto option_enum = StringAsEnum<Option>(option.GetString());
      if (option_enum.is_error()) {
        return option_enum.take_error_result();
      }
      descriptor.options.insert(option_enum.take_value());
    }
  }

  return fit::ok(descriptor);
}

fit::result<std::vector<uint8_t>, std::string> VolumeDescriptor::Serialize() const {
  rapidjson::Document document;
  document.SetObject();

  document.AddMember("magic", kMagic, document.GetAllocator());
  auto instance_str = Guid::ToString(instance);
  if (instance_str.is_error()) {
    return instance_str.take_error_result();
  }
  document.AddMember("instance_guid", instance_str.take_value(), document.GetAllocator());

  auto type_str = Guid::ToString(type);
  if (type_str.is_error()) {
    return type_str.take_error_result();
  }
  document.AddMember("type_guid", type_str.take_value(), document.GetAllocator());
  document.AddMember("name", name, document.GetAllocator());
  document.AddMember("block_size", block_size, document.GetAllocator());
  document.AddMember("encryption_type", EnumAsString(encryption), document.GetAllocator());

  if (!options.empty()) {
    rapidjson::Value option_set;
    option_set.SetArray();
    for (const auto& option : options) {
      rapidjson::Value value(EnumAsString(option).c_str(), document.GetAllocator());
      option_set.PushBack(value, document.GetAllocator());
    }
    document.AddMember("options", option_set, document.GetAllocator());
  }

  rapidjson::StringBuffer buffer;
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
  if (!document.Accept(writer)) {
    return fit::error("Failed to obtain string representation of VolumeDescriptor.\n");
  }

  const auto* serialized_content = reinterpret_cast<const uint8_t*>(buffer.GetString());
  std::vector<uint8_t> data(serialized_content, serialized_content + buffer.GetLength());
  data.push_back('\0');

  return fit::ok(data);
}

}  // namespace storage::volume_image
