// Copyright 2021 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 <fcntl.h>
#include <lib/fpromise/result.h>
#include <sys/stat.h>

#include <cstdint>
#include <cstdio>
#include <iostream>
#include <memory>
#include <string>

#include <fbl/unique_fd.h>

#include "src/storage/volume_image/adapter/commands.h"
#include "src/storage/volume_image/fvm/fvm_descriptor.h"
#include "src/storage/volume_image/fvm/fvm_sparse_image.h"
#include "src/storage/volume_image/utils/block_writer.h"
#include "src/storage/volume_image/utils/bounded_writer.h"
#include "src/storage/volume_image/utils/fd_reader.h"
#include "src/storage/volume_image/utils/fd_writer.h"

namespace storage::volume_image {
namespace {

fpromise::result<struct stat, std::string> GetBlockInfo(std::string_view path) {
  std::string str_path(path);
  fbl::unique_fd device(open(str_path.c_str(), O_RDONLY));

  if (!device.is_valid()) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to obtain FD for device at " + str_path +
                           ". More specifically: " + err + ".");
  }

  struct stat st = {};
  if (fstat(device.get(), &st) != 0) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to perform fstat on device. More specifically: " + err + ".");
  }

  return fpromise::ok(st);
}

fpromise::result<uint64_t, std::string> GetSize(std::string_view path) {
  std::string str_path(path);
  fbl::unique_fd device(open(str_path.c_str(), O_RDONLY));

  if (!device.is_valid()) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to obtain FD for device at " + str_path +
                           ". More specifically: " + err + ".");
  }

  off_t ret = lseek(device.get(), 0, SEEK_END);
  if (ret < 0) {
    auto err = std::string(strerror(errno));
    return fpromise::error("Failed to seek to end of stream at " + str_path +
                           ". More specifically: " + err + ".");
  }

  return fpromise::ok(static_cast<uint64_t>(ret));
}

}  // namespace

fpromise::result<void, std::string> Pave(const PaveParams& params) {
  if (params.output_path.empty()) {
    return fpromise::error("No image output path provided for Pave.");
  }

  if (params.input_path.empty()) {
    return fpromise::error(
        "No image input path provided for Pave. Must provide path to sparse fvm image.");
  }

  if (params.is_output_embedded) {
    if (!params.offset.has_value()) {
      return fpromise::error("Must provide offset for embedding fvm image.");
    }

    // For block devices we use remaining space.
    if (!params.length.has_value() && params.type == TargetType::kFile) {
      return fpromise::error("Must provide length for embedding fvm image.");
    }
  }

  std::unique_ptr<Writer> writer = nullptr;
  // Depending on target device we may use a different default value.
  std::optional<uint64_t> default_target_length;

  switch (params.type) {
    case TargetType::kBlockDevice: {
      auto writer_or = FdWriter::Create(params.output_path);
      if (writer_or.is_error()) {
        return writer_or.take_error_result();
      }
      std::unique_ptr<FdWriter> fd_writer = std::make_unique<FdWriter>(writer_or.take_value());

      auto reader_or = FdReader::Create(params.output_path);
      if (reader_or.is_error()) {
        return reader_or.take_error_result();
      }
      std::unique_ptr<FdReader> fd_reader = std::make_unique<FdReader>(reader_or.take_value());
      auto block_info_or = GetBlockInfo(params.output_path);
      if (block_info_or.is_error()) {
        return block_info_or.take_error_result();
      }

      if (params.offset.has_value() &&
          params.offset.value() % block_info_or.value().st_blksize != 0) {
        return fpromise::error(
            "Offset must be aligned to block boundary for paving a block device.");
      }

      auto size_or = GetSize(params.output_path);
      if (size_or.is_error()) {
        return size_or.take_error_result();
      }
      default_target_length = size_or.take_value() - params.offset.value_or(0);
      uint64_t block_count =
          params.length.value_or(default_target_length.value()) / block_info_or.value().st_blksize;
      writer = std::make_unique<BlockWriter>(block_info_or.value().st_blksize, block_count,
                                             std::move(fd_reader), std::move(fd_writer));
      break;
    }

    case TargetType::kFile: {
      auto writer_or = FdWriter::Create(params.output_path);
      if (writer_or.is_error()) {
        return writer_or.take_error_result();
      }
      auto size_or = GetSize(params.output_path);
      if (size_or.is_error()) {
        return size_or.take_error_result();
      }
      default_target_length = size_or.value() - params.offset.value_or(0);
      writer = std::make_unique<FdWriter>(writer_or.take_value());
      break;
    }
  };

  auto reader_or = FdReader::Create(params.input_path);
  if (reader_or.is_error()) {
    return reader_or.take_error_result();
  }
  std::unique_ptr<Reader> reader = std::make_unique<FdReader>(reader_or.take_value());
  auto length = params.length.value_or(default_target_length.value());

  if (params.is_output_embedded) {
    writer = std::make_unique<BoundedWriter>(std::move(writer), params.offset.value(), length);
  }

  auto descriptor_or = FvmSparseReadImage(0, std::move(reader));
  if (descriptor_or.is_error()) {
    return descriptor_or.take_error_result();
  }

  // So we can update the options.
  auto updated_options = descriptor_or.value().options();

  updated_options.target_volume_size = length;
  if (updated_options.max_volume_size.value_or(0) <
      params.fvm_options.max_volume_size.value_or(0)) {
    updated_options.max_volume_size = params.fvm_options.max_volume_size;
  }
  updated_options.compression = {.schema = CompressionSchema::kNone};

  auto updated_descriptor_or =
      FvmDescriptor::Builder(descriptor_or.take_value()).SetOptions(updated_options).Build();
  if (updated_descriptor_or.is_error()) {
    return updated_descriptor_or.take_error_result();
  }

  auto pave_result = updated_descriptor_or.value().WriteBlockImage(*writer);
  if (pave_result.is_error()) {
    return pave_result.take_error_result();
  }

  return fpromise::ok();
}

}  // namespace storage::volume_image
