/*
 * Copyright 2026 Snowflake Inc.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed 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.
 */

#pragma once

/// @file json.hpp
///
/// Convenience overloads for appending structured data to a channel without
/// manually serialising to NDJSON.
///
/// Include this header (in addition to channel.hpp) when you want to work with
/// JSON objects directly.  The underlying JSON library is an implementation
/// detail — use snowflake::ingest::streaming::json rather than nlohmann::json
/// in application code to remain insulated from future library changes.
///
/// Performance note: these helpers serialise each object via json::dump().
/// If you already produce NDJSON from your own serialisation stack, call
/// channel::append_rows(std::string_view, ...) directly to avoid the
/// intermediate allocation.

#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include "nlohmann/json.hpp"
#include "snowflake/ingest/streaming/channel.hpp"

namespace snowflake::ingest::streaming {

/// JSON value type.  Backed by nlohmann/json; the underlying library is an
/// implementation detail subject to change in future releases.
using json = nlohmann::json;

/// Append a single JSON object to the channel.
///
/// @param ch               The channel to write to.
/// @param row              A JSON object representing one row.
/// @param offset_token     Optional offset token for this row (used as both
///                         start and end token).
inline result<void> append_row(
    channel& ch, const json& row,
    std::optional<std::string_view> offset_token = std::nullopt) {
  std::string ndjson = row.dump() + "\n";
  return ch.append_rows(ndjson, 1, offset_token, offset_token);
}

/// Append multiple JSON objects to the channel in a single batch.
///
/// @param ch                    The channel to write to.
/// @param rows                  JSON objects, one per row.
/// @param start_offset_token    Optional token for the first row in the batch.
/// @param end_offset_token      Optional token for the last row in the batch.
inline result<void> append_rows(
    channel& ch, const std::vector<json>& rows,
    std::optional<std::string_view> start_offset_token = std::nullopt,
    std::optional<std::string_view> end_offset_token = std::nullopt) {
  std::string ndjson;
  ndjson.reserve(rows.size() * 64);  // rough pre-size to reduce reallocations
  for (const auto& row : rows) {
    ndjson += row.dump();
    ndjson += '\n';
  }
  return ch.append_rows(ndjson, static_cast<int64_t>(rows.size()),
                        start_offset_token, end_offset_token);
}

}  // namespace snowflake::ingest::streaming
