/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include "iceberg/snapshot.h"

#include <memory>
#include <sstream>
#include <utility>

#include "iceberg/file_io.h"
#include "iceberg/manifest/manifest_entry.h"
#include "iceberg/manifest/manifest_list.h"
#include "iceberg/manifest/manifest_reader.h"
#include "iceberg/util/macros.h"
#include "iceberg/util/string_util.h"

namespace iceberg {

namespace {

/// \brief Helper function to conditionally add a property to the summary
template <typename T>
void SetIf(bool condition, std::unordered_map<std::string, std::string>& builder,
           const std::string& property, T value) {
  if (condition) {
    if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
                  std::is_convertible_v<T, std::string_view>) {
      builder[property] = value;
    } else {
      builder[property] = std::to_string(value);
    }
  }
}

}  // namespace

bool SnapshotRef::Branch::Equals(const SnapshotRef::Branch& other) const {
  return min_snapshots_to_keep == other.min_snapshots_to_keep &&
         max_snapshot_age_ms == other.max_snapshot_age_ms &&
         max_ref_age_ms == other.max_ref_age_ms;
}

bool SnapshotRef::Tag::Equals(const SnapshotRef::Tag& other) const {
  return max_ref_age_ms == other.max_ref_age_ms;
}

SnapshotRefType SnapshotRef::type() const noexcept {
  return std::visit(
      [&](const auto& retention) -> SnapshotRefType {
        using T = std::remove_cvref_t<decltype(retention)>;
        if constexpr (std::is_same_v<T, Branch>) {
          return SnapshotRefType::kBranch;
        } else {
          return SnapshotRefType::kTag;
        }
      },
      retention);
}

std::optional<int64_t> SnapshotRef::max_ref_age_ms() const noexcept {
  return std::visit(
      [&](const auto& retention) -> std::optional<int64_t> {
        using T = std::remove_cvref_t<decltype(retention)>;
        if constexpr (std::is_same_v<T, Branch>) {
          return retention.max_ref_age_ms;
        } else {
          return retention.max_ref_age_ms;
        }
      },
      retention);
}

Status SnapshotRef::Validate() const {
  if (type() == SnapshotRefType::kBranch) {
    const auto& branch = std::get<Branch>(this->retention);
    ICEBERG_CHECK(!branch.min_snapshots_to_keep.has_value() ||
                      branch.min_snapshots_to_keep.value() > 0,
                  "Min snapshots to keep must be greater than 0");
    ICEBERG_CHECK(
        !branch.max_snapshot_age_ms.has_value() || branch.max_snapshot_age_ms.value() > 0,
        "Max snapshot age must be greater than 0 ms");
    ICEBERG_CHECK(!branch.max_ref_age_ms.has_value() || branch.max_ref_age_ms.value() > 0,
                  "Max reference age must be greater than 0");
  } else {
    const auto& tag = std::get<Tag>(this->retention);
    ICEBERG_CHECK(!tag.max_ref_age_ms.has_value() || tag.max_ref_age_ms.value() > 0,
                  "Max reference age must be greater than 0");
  }
  return {};
}

Result<std::unique_ptr<SnapshotRef>> SnapshotRef::MakeBranch(
    int64_t snapshot_id, std::optional<int32_t> min_snapshots_to_keep,
    std::optional<int64_t> max_snapshot_age_ms, std::optional<int64_t> max_ref_age_ms) {
  auto ref = std::make_unique<SnapshotRef>(
      SnapshotRef{.snapshot_id = snapshot_id,
                  .retention = Branch{
                      .min_snapshots_to_keep = min_snapshots_to_keep,
                      .max_snapshot_age_ms = max_snapshot_age_ms,
                      .max_ref_age_ms = max_ref_age_ms,
                  }});
  ICEBERG_RETURN_UNEXPECTED(ref->Validate());
  return ref;
}

Result<std::unique_ptr<SnapshotRef>> SnapshotRef::MakeTag(
    int64_t snapshot_id, std::optional<int64_t> max_ref_age_ms) {
  auto ref = std::make_unique<SnapshotRef>(SnapshotRef{
      .snapshot_id = snapshot_id, .retention = Tag{.max_ref_age_ms = max_ref_age_ms}});
  ICEBERG_RETURN_UNEXPECTED(ref->Validate());
  return ref;
}

std::unique_ptr<SnapshotRef> SnapshotRef::Clone(
    std::optional<int64_t> new_snapshot_id) const {
  auto ref = std::make_unique<SnapshotRef>();
  ref->snapshot_id = new_snapshot_id.value_or(snapshot_id);
  ref->retention = retention;
  return ref;
}

bool SnapshotRef::Equals(const SnapshotRef& other) const {
  if (this == &other) {
    return true;
  }
  if (type() != other.type()) {
    return false;
  }

  if (type() == SnapshotRefType::kBranch) {
    return snapshot_id == other.snapshot_id &&
           std::get<Branch>(retention) == std::get<Branch>(other.retention);

  } else {
    return snapshot_id == other.snapshot_id &&
           std::get<Tag>(retention) == std::get<Tag>(other.retention);
  }
}

std::optional<std::string_view> Snapshot::Operation() const {
  auto it = summary.find(SnapshotSummaryFields::kOperation);
  if (it != summary.end()) {
    return it->second;
  }
  return std::nullopt;
}

Result<std::optional<int64_t>> Snapshot::FirstRowId() const { return first_row_id; }

Result<std::optional<int64_t>> Snapshot::AddedRows() const { return added_rows; }

bool Snapshot::Equals(const Snapshot& other) const {
  if (this == &other) {
    return true;
  }
  return snapshot_id == other.snapshot_id &&
         parent_snapshot_id == other.parent_snapshot_id &&
         sequence_number == other.sequence_number && timestamp_ms == other.timestamp_ms &&
         schema_id == other.schema_id && first_row_id == other.first_row_id &&
         added_rows == other.added_rows;
}

Result<std::unique_ptr<Snapshot>> Snapshot::Make(
    int64_t sequence_number, int64_t snapshot_id,
    std::optional<int64_t> parent_snapshot_id, TimePointMs timestamp_ms,
    std::string operation, std::unordered_map<std::string, std::string> summary,
    std::optional<int32_t> schema_id, std::string manifest_list,
    std::optional<int64_t> first_row_id, std::optional<int64_t> added_rows) {
  ICEBERG_PRECHECK(!operation.empty(), "Operation cannot be empty");
  ICEBERG_PRECHECK(!first_row_id.has_value() || first_row_id.value() >= 0,
                   "Invalid first-row-id (cannot be negative): {}", first_row_id.value());
  ICEBERG_PRECHECK(!added_rows.has_value() || added_rows.value() >= 0,
                   "Invalid added-rows (cannot be negative): {}", added_rows.value());
  ICEBERG_PRECHECK(!first_row_id.has_value() || added_rows.has_value(),
                   "Missing added-rows when first-row-id is set");
  summary[SnapshotSummaryFields::kOperation] = operation;
  return std::make_unique<Snapshot>(Snapshot{
      .snapshot_id = snapshot_id,
      .parent_snapshot_id = parent_snapshot_id,
      .sequence_number = sequence_number,
      .timestamp_ms = timestamp_ms,
      .manifest_list = std::move(manifest_list),
      .summary = std::move(summary),
      .schema_id = schema_id,
      .first_row_id = first_row_id,
      .added_rows = first_row_id.has_value() ? added_rows : std::nullopt,
  });
}

Result<SnapshotReader::ManifestsCache> SnapshotReader::InitManifestsCache(
    const Snapshot* snapshot, std::shared_ptr<FileIO> file_io) {
  if (file_io == nullptr) {
    return InvalidArgument("Cannot cache manifests: FileIO is null");
  }

  // Read manifest list
  ICEBERG_ASSIGN_OR_RAISE(auto reader,
                          ManifestListReader::Make(snapshot->manifest_list, file_io));
  ICEBERG_ASSIGN_OR_RAISE(auto manifest_files, reader->Files());

  std::vector<ManifestFile> manifests;
  manifests.reserve(manifest_files.size());

  // Partition manifests: data manifests first, then delete manifests
  // First pass: collect data manifests
  for (const auto& manifest_file : manifest_files) {
    if (manifest_file.content == ManifestContent::kData) {
      manifests.push_back(manifest_file);
    }
  }
  size_t data_manifests_count = manifests.size();

  // Second pass: append delete manifests
  for (const auto& manifest_file : manifest_files) {
    if (manifest_file.content == ManifestContent::kDeletes) {
      manifests.push_back(manifest_file);
    }
  }

  return std::make_pair(std::move(manifests), data_manifests_count);
}

Result<std::span<ManifestFile>> SnapshotReader::Manifests(
    std::shared_ptr<FileIO> file_io) const {
  ICEBERG_ASSIGN_OR_RAISE(auto cache_ref, manifests_cache_.Get(snapshot_, file_io));
  auto& cache = cache_ref.get();
  return std::span<ManifestFile>(cache.first.data(), cache.first.size());
}

Result<std::span<ManifestFile>> SnapshotReader::DataManifests(
    std::shared_ptr<FileIO> file_io) const {
  ICEBERG_ASSIGN_OR_RAISE(auto cache_ref, manifests_cache_.Get(snapshot_, file_io));
  auto& cache = cache_ref.get();
  return std::span<ManifestFile>(cache.first.data(), cache.second);
}

Result<std::span<ManifestFile>> SnapshotReader::DeleteManifests(
    std::shared_ptr<FileIO> file_io) const {
  ICEBERG_ASSIGN_OR_RAISE(auto cache_ref, manifests_cache_.Get(snapshot_, file_io));
  auto& cache = cache_ref.get();
  const size_t delete_start = cache.second;
  const size_t delete_count = cache.first.size() - delete_start;
  return std::span<ManifestFile>(cache.first.data() + delete_start, delete_count);
}

// SnapshotSummaryBuilder::UpdateMetrics implementation

void SnapshotSummaryBuilder::UpdateMetrics::Clear() {
  added_size_ = 0;
  removed_size_ = 0;
  added_files_ = 0;
  removed_files_ = 0;
  added_eq_delete_files_ = 0;
  removed_eq_delete_files_ = 0;
  added_pos_delete_files_ = 0;
  removed_pos_delete_files_ = 0;
  added_delete_files_ = 0;
  removed_delete_files_ = 0;
  added_dvs_ = 0;
  removed_dvs_ = 0;
  added_records_ = 0;
  deleted_records_ = 0;
  added_pos_deletes_ = 0;
  removed_pos_deletes_ = 0;
  added_eq_deletes_ = 0;
  removed_eq_deletes_ = 0;
  trust_size_and_delete_counts_ = true;
}

void SnapshotSummaryBuilder::UpdateMetrics::AddTo(
    std::unordered_map<std::string, std::string>& builder) const {
  SetIf(added_files_ > 0, builder, SnapshotSummaryFields::kAddedDataFiles, added_files_);
  SetIf(removed_files_ > 0, builder, SnapshotSummaryFields::kDeletedDataFiles,
        removed_files_);
  SetIf(added_eq_delete_files_ > 0, builder, SnapshotSummaryFields::kAddedEqDeleteFiles,
        added_eq_delete_files_);
  SetIf(removed_eq_delete_files_ > 0, builder,
        SnapshotSummaryFields::kRemovedEqDeleteFiles, removed_eq_delete_files_);
  SetIf(added_pos_delete_files_ > 0, builder, SnapshotSummaryFields::kAddedPosDeleteFiles,
        added_pos_delete_files_);
  SetIf(removed_pos_delete_files_ > 0, builder,
        SnapshotSummaryFields::kRemovedPosDeleteFiles, removed_pos_delete_files_);
  SetIf(added_delete_files_ > 0, builder, SnapshotSummaryFields::kAddedDeleteFiles,
        added_delete_files_);
  SetIf(removed_delete_files_ > 0, builder, SnapshotSummaryFields::kRemovedDeleteFiles,
        removed_delete_files_);
  SetIf(added_dvs_ > 0, builder, SnapshotSummaryFields::kAddedDVs, added_dvs_);
  SetIf(removed_dvs_ > 0, builder, SnapshotSummaryFields::kRemovedDVs, removed_dvs_);
  SetIf(added_records_ > 0, builder, SnapshotSummaryFields::kAddedRecords,
        added_records_);
  SetIf(deleted_records_ > 0, builder, SnapshotSummaryFields::kDeletedRecords,
        deleted_records_);

  if (trust_size_and_delete_counts_) {
    SetIf(added_size_ > 0, builder, SnapshotSummaryFields::kAddedFileSize, added_size_);
    SetIf(removed_size_ > 0, builder, SnapshotSummaryFields::kRemovedFileSize,
          removed_size_);
    SetIf(added_pos_deletes_ > 0, builder, SnapshotSummaryFields::kAddedPosDeletes,
          added_pos_deletes_);
    SetIf(removed_pos_deletes_ > 0, builder, SnapshotSummaryFields::kRemovedPosDeletes,
          removed_pos_deletes_);
    SetIf(added_eq_deletes_ > 0, builder, SnapshotSummaryFields::kAddedEqDeletes,
          added_eq_deletes_);
    SetIf(removed_eq_deletes_ > 0, builder, SnapshotSummaryFields::kRemovedEqDeletes,
          removed_eq_deletes_);
  }
}

void SnapshotSummaryBuilder::UpdateMetrics::AddedFile(const DataFile& file) {
  added_size_ += file.file_size_in_bytes;

  switch (file.content) {
    case DataFile::Content::kData:
      added_files_ += 1;
      added_records_ += file.record_count;
      break;
    case DataFile::Content::kPositionDeletes:
      if (file.IsDeletionVector()) {
        added_dvs_ += 1;
      } else {
        added_pos_delete_files_ += 1;
      }
      added_delete_files_ += 1;
      added_pos_deletes_ += file.record_count;
      break;
    case DataFile::Content::kEqualityDeletes:
      added_delete_files_ += 1;
      added_eq_delete_files_ += 1;
      added_eq_deletes_ += file.record_count;
      break;
    default:
      std::unreachable();
  }
}

void SnapshotSummaryBuilder::UpdateMetrics::RemovedFile(const DataFile& file) {
  removed_size_ += file.file_size_in_bytes;

  switch (file.content) {
    case DataFile::Content::kData:
      removed_files_ += 1;
      deleted_records_ += file.record_count;
      break;
    case DataFile::Content::kPositionDeletes:
      if (file.IsDeletionVector()) {
        removed_dvs_ += 1;
      } else {
        removed_pos_delete_files_ += 1;
      }
      removed_delete_files_ += 1;
      removed_pos_deletes_ += file.record_count;
      break;
    case DataFile::Content::kEqualityDeletes:
      removed_delete_files_ += 1;
      removed_eq_delete_files_ += 1;
      removed_eq_deletes_ += file.record_count;
      break;
    default:
      std::unreachable();
  }
}

void SnapshotSummaryBuilder::UpdateMetrics::AddedManifest(const ManifestFile& manifest) {
  switch (manifest.content) {
    case ManifestContent::kData:
      added_files_ += manifest.added_files_count.value_or(0);
      added_records_ += manifest.added_rows_count.value_or(0);
      removed_files_ += manifest.deleted_files_count.value_or(0);
      deleted_records_ += manifest.deleted_rows_count.value_or(0);
      break;
    case ManifestContent::kDeletes:
      added_delete_files_ += manifest.added_files_count.value_or(0);
      removed_delete_files_ += manifest.deleted_files_count.value_or(0);
      trust_size_and_delete_counts_ = false;
      break;
    default:
      std::unreachable();
  }
}

void SnapshotSummaryBuilder::UpdateMetrics::Merge(const UpdateMetrics& other) {
  added_files_ += other.added_files_;
  removed_files_ += other.removed_files_;
  added_eq_delete_files_ += other.added_eq_delete_files_;
  removed_eq_delete_files_ += other.removed_eq_delete_files_;
  added_pos_delete_files_ += other.added_pos_delete_files_;
  removed_pos_delete_files_ += other.removed_pos_delete_files_;
  added_dvs_ += other.added_dvs_;
  removed_dvs_ += other.removed_dvs_;
  added_delete_files_ += other.added_delete_files_;
  removed_delete_files_ += other.removed_delete_files_;
  added_size_ += other.added_size_;
  removed_size_ += other.removed_size_;
  added_records_ += other.added_records_;
  deleted_records_ += other.deleted_records_;
  added_pos_deletes_ += other.added_pos_deletes_;
  removed_pos_deletes_ += other.removed_pos_deletes_;
  added_eq_deletes_ += other.added_eq_deletes_;
  removed_eq_deletes_ += other.removed_eq_deletes_;
  trust_size_and_delete_counts_ =
      trust_size_and_delete_counts_ && other.trust_size_and_delete_counts_;
}

// SnapshotSummaryBuilder implementation

void SnapshotSummaryBuilder::Clear() {
  partition_metrics_.clear();
  metrics_.Clear();
  deleted_duplicate_files_ = 0;
  trust_partition_metrics_ = true;
}

void SnapshotSummaryBuilder::SetPartitionSummaryLimit(int32_t max) {
  max_changed_partitions_for_summaries_ = max;
}

void SnapshotSummaryBuilder::IncrementDuplicateDeletes(int32_t increment) {
  deleted_duplicate_files_ += increment;
}

Status SnapshotSummaryBuilder::AddedFile(const PartitionSpec& spec,
                                         const DataFile& file) {
  metrics_.AddedFile(file);
  ICEBERG_RETURN_UNEXPECTED(UpdatePartitions(spec, file, true));
  return {};
}

Status SnapshotSummaryBuilder::DeletedFile(const PartitionSpec& spec,
                                           const DataFile& file) {
  metrics_.RemovedFile(file);
  ICEBERG_RETURN_UNEXPECTED(UpdatePartitions(spec, file, false));
  return {};
}

void SnapshotSummaryBuilder::AddedManifest(const ManifestFile& manifest) {
  trust_partition_metrics_ = false;
  partition_metrics_.clear();
  metrics_.AddedManifest(manifest);
}

void SnapshotSummaryBuilder::Set(const std::string& property, const std::string& value) {
  properties_[property] = value;
}

void SnapshotSummaryBuilder::Merge(const SnapshotSummaryBuilder& other) {
  for (const auto& [key, value] : other.properties_) {
    properties_[key] = value;
  }
  metrics_.Merge(other.metrics_);

  trust_partition_metrics_ = trust_partition_metrics_ && other.trust_partition_metrics_;
  if (trust_partition_metrics_) {
    for (const auto& [key, value] : other.partition_metrics_) {
      partition_metrics_[key].Merge(value);
    }
  } else {
    partition_metrics_.clear();
  }

  deleted_duplicate_files_ += other.deleted_duplicate_files_;
}

std::unordered_map<std::string, std::string> SnapshotSummaryBuilder::Build() const {
  std::unordered_map<std::string, std::string> builder;

  // Copy custom summary properties
  builder.insert(properties_.begin(), properties_.end());

  metrics_.AddTo(builder);

  SetIf(deleted_duplicate_files_ > 0, builder,
        SnapshotSummaryFields::kDeletedDuplicatedFiles, deleted_duplicate_files_);

  SetIf(trust_partition_metrics_, builder,
        SnapshotSummaryFields::kChangedPartitionCountProp, partition_metrics_.size());

  // Add partition summaries if enabled
  if (trust_partition_metrics_ && max_changed_partitions_for_summaries_ >= 0 &&
      partition_metrics_.size() <=
          static_cast<size_t>(max_changed_partitions_for_summaries_)) {
    SetIf(!partition_metrics_.empty(), builder,
          SnapshotSummaryFields::kPartitionSummaryProp, "true");
    for (const auto& [key, metrics] : partition_metrics_) {
      if (!key.empty()) {
        builder[SnapshotSummaryFields::kChangedPartitionPrefix + key] =
            PartitionSummary(metrics);
      }
    }
  }

  return builder;
}

Status SnapshotSummaryBuilder::UpdatePartitions(const PartitionSpec& spec,
                                                const DataFile& file, bool is_addition) {
  if (trust_partition_metrics_) {
    ICEBERG_ASSIGN_OR_RAISE(std::string partition_path,
                            spec.PartitionPath(file.partition));
    auto& part_metrics = partition_metrics_[partition_path];
    if (is_addition) {
      part_metrics.AddedFile(file);
    } else {
      part_metrics.RemovedFile(file);
    }
  }
  return {};
}

std::string SnapshotSummaryBuilder::PartitionSummary(const UpdateMetrics& metrics) const {
  std::unordered_map<std::string, std::string> part_builder;
  metrics.AddTo(part_builder);

  // Format as comma-separated key=value pairs
  std::ostringstream oss;
  bool first = true;
  for (const auto& [key, value] : part_builder) {
    if (!first) {
      oss << ",";
    }
    oss << key << "=" << value;
    first = false;
  }
  return oss.str();
}

}  // namespace iceberg
