/*
 * 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 "common/tsfile_common.h"

#include <algorithm>
#include <map>

#include "common/logger/elog.h"
#include "common/schema.h"

using namespace common;
namespace storage {

const char* MAGIC_STRING_TSFILE = "TsFile";
const char VERSION_NUM_BYTE = 0x04;  // 0x03;
const char CHUNK_GROUP_HEADER_MARKER = 0;
const char CHUNK_HEADER_MARKER = 1;
const char ONLY_ONE_PAGE_CHUNK_HEADER_MARKER = 5;
const char SEPARATOR_MARKER = 2;
const char OPERATION_INDEX_RANGE = 4;

/* ================ TimeseriesIndex ================ */
int TimeseriesIndex::add_chunk_meta(ChunkMeta* chunk_meta,
                                    bool serialize_statistic) {
    int ret = E_OK;
    if (IS_NULL(chunk_meta)) {
        ret = E_INVALID_ARG;
    } else if (RET_FAIL(chunk_meta->serialize_to(
                   chunk_meta_list_serialized_buf_, serialize_statistic))) {
    } else if (RET_FAIL(statistic_->merge_with(chunk_meta->statistic_))) {
    }
    return ret;
}

/* ================ TSMIterator ================ */
int TSMIterator::init() {
    // sort chunk_group_meta_list_ ： {[measurementA, offsetA1], [measurementB,
    // offsetB1], [measurementA, offsetA2], [measurementB, offsetB2]} ->
    // {[measurementA, offsetA1], [measurementA, offsetA2], [measurementB,
    // offsetB1], [measurementB, offsetB2]}
    for (auto chunk_group_meta_iter = chunk_group_meta_list_.begin();
         chunk_group_meta_iter != chunk_group_meta_list_.end();
         chunk_group_meta_iter++) {
        auto chunk_meta_list = chunk_group_meta_iter.get()->chunk_meta_list_;
        // Use a map to group chunks by measurement_name_
        std::map<common::String, std::vector<ChunkMeta*>> groups;
        std::vector<common::String> order;
        for (auto it = chunk_meta_list.begin(); it != chunk_meta_list.end();
             it++) {
            auto* chunk_meta = it.get();
            if (groups.find(chunk_meta->measurement_name_) == groups.end()) {
                order.push_back(chunk_meta->measurement_name_);
            }
            groups[chunk_meta->measurement_name_].push_back(chunk_meta);
        }

        // Sort each group of chunk metas by offset
        for (auto it = groups.begin(); it != groups.end(); ++it) {
            std::vector<ChunkMeta*>& group = it->second;
            std::sort(group.begin(), group.end(),
                      [](ChunkMeta* a, ChunkMeta* b) {
                          return a->offset_of_chunk_header_ <
                                 b->offset_of_chunk_header_;
                      });
        }
        // Clear and refill chunk_group_meta_list
        chunk_group_meta_iter.get()->chunk_meta_list_.clear();
        for (const auto& measurement_name : order) {
            for (auto chunk_meta : groups[measurement_name]) {
                chunk_group_meta_iter.get()->chunk_meta_list_.push_back(
                    chunk_meta);
            }
        }
    }

    // FIXME empty list
    chunk_group_meta_iter_ = chunk_group_meta_list_.begin();
    while (chunk_group_meta_iter_ != chunk_group_meta_list_.end()) {
        chunk_meta_iter_ =
            chunk_group_meta_iter_.get()->chunk_meta_list_.begin();
        std::map<common::String, std::vector<ChunkMeta*>> tmp;
        while (chunk_meta_iter_ !=
               chunk_group_meta_iter_.get()->chunk_meta_list_.end()) {
            tmp[chunk_meta_iter_.get()->measurement_name_].emplace_back(
                chunk_meta_iter_.get());
            chunk_meta_iter_++;
        }
        if (!tmp.empty()) {
            tsm_chunk_meta_info_[chunk_group_meta_iter_.get()->device_id_] =
                tmp;
        }

        chunk_group_meta_iter_++;
    }
    if (!tsm_chunk_meta_info_.empty() &&
        !tsm_chunk_meta_info_.begin()->second.empty()) {
        tsm_measurement_iter_ = tsm_chunk_meta_info_.begin()->second.begin();
    }
    tsm_device_iter_ = tsm_chunk_meta_info_.begin();
    return E_OK;
}

bool TSMIterator::has_next() const {
    return tsm_device_iter_ != tsm_chunk_meta_info_.end();
}

int TSMIterator::get_next(std::shared_ptr<IDeviceID>& ret_device_id,
                          String& ret_measurement_name,
                          TimeseriesIndex& ret_ts_index) {
    int ret = E_OK;
    SimpleList<ChunkMeta*> chunk_meta_list_of_this_ts(
        1024, MOD_TIMESERIES_INDEX_OBJ);  // FIXME
    if (tsm_measurement_iter_ == tsm_device_iter_->second.end()) {
        tsm_device_iter_++;
        if (!has_next()) {
            return E_NO_MORE_DATA;
        } else {
            tsm_measurement_iter_ = tsm_device_iter_->second.begin();
        }
    }
    ret_device_id = tsm_device_iter_->first;
    ret_measurement_name.shallow_copy_from(tsm_measurement_iter_->first);
    for (auto meta : tsm_measurement_iter_->second) {
        chunk_meta_list_of_this_ts.push_back(meta);
    }
    if (chunk_meta_list_of_this_ts.size() == 0) {
        return E_TSFILE_WRITER_META_ERR;
    }

    const bool multi_chunks = chunk_meta_list_of_this_ts.size() > 1;
    ChunkMeta* first_chunk_meta = chunk_meta_list_of_this_ts.front();
    const char meta_type = (multi_chunks ? 1 : 0) | (first_chunk_meta->mask_);
    const TSDataType data_type = first_chunk_meta->data_type_;

    ret_ts_index.set_ts_meta_type(meta_type);
    ret_ts_index.set_measurement_name(ret_measurement_name);
    ret_ts_index.set_data_type(data_type);
    ret_ts_index.init_statistic(data_type);

    SimpleList<ChunkMeta*>::Iterator ts_chunk_meta_iter =
        chunk_meta_list_of_this_ts.begin();
    for (;
         IS_SUCC(ret) && ts_chunk_meta_iter != chunk_meta_list_of_this_ts.end();
         ts_chunk_meta_iter++) {
        ChunkMeta* chunk_meta = ts_chunk_meta_iter.get();
        if (RET_FAIL(ret_ts_index.add_chunk_meta(chunk_meta, multi_chunks))) {
        }
    }
    if (IS_SUCC(ret)) {
        ret_ts_index.finish();
    }
    if (UNLIKELY(ret_device_id == nullptr)) {
        ret = E_TSFILE_WRITER_META_ERR;
        // log_err("null device name from chunk_group_meta_iter, ret=%d", ret);
        ASSERT(false);
    }
    tsm_measurement_iter_++;
    return ret;
}

int TsFileMeta::serialize_to(common::ByteStream& out) {
    auto start_idx = out.total_size();
    common::SerializationUtil::write_var_uint(
        table_metadata_index_node_map_.size(), out);
    for (auto& idx_nodes_iter : table_metadata_index_node_map_) {
        common::SerializationUtil::write_var_str(idx_nodes_iter.first, out);
        idx_nodes_iter.second->serialize_to(out);
    }

    common::SerializationUtil::write_var_uint(table_schemas_.size(), out);
    for (auto& table_schema_iter : table_schemas_) {
        common::SerializationUtil::write_var_str(table_schema_iter.first, out);
        table_schema_iter.second->serialize_to(out);
    }

    common::SerializationUtil::write_i64(meta_offset_, out);

    if (bloom_filter_ != nullptr) {
        bloom_filter_->serialize_to(out);
    } else {
        common::SerializationUtil::write_ui8(0, out);
    }

    common::SerializationUtil::write_var_int(tsfile_properties_.size(), out);
    for (const auto& tsfile_property : tsfile_properties_) {
        common::SerializationUtil::write_var_str(tsfile_property.first, out);
        common::SerializationUtil::write_var_char_ptr(tsfile_property.second,
                                                      out);
    }

    return out.total_size() - start_idx;
}

int TsFileMeta::deserialize_from(common::ByteStream& in) {
    int ret = common::E_OK;
    void* index_node_buf = page_arena_->alloc(sizeof(MetaIndexNode));
    void* bloom_filter_buf = page_arena_->alloc(sizeof(BloomFilter));
    if (IS_NULL(index_node_buf) || IS_NULL(bloom_filter_buf)) {
        return common::E_OOM;
    }

    bloom_filter_ = new (bloom_filter_buf) BloomFilter();

#ifdef DEBUG_SE
    DEBUG_print_byte_stream("tsfile_meta = ", in);
#endif

    uint32_t index_node_map_size = 0;
    SerializationUtil::read_var_uint(index_node_map_size, in);
    for (uint32_t i = 0; i < index_node_map_size; i++) {
        std::string key;
        common::SerializationUtil::read_var_str(key, in);
        auto value = std::make_shared<MetaIndexNode>(page_arena_);
        value->device_deserialize_from(in);
        table_metadata_index_node_map_.emplace(key, std::move(value));
    }

    uint32_t table_schemas_size = 0;
    common::SerializationUtil::read_var_uint(table_schemas_size, in);
    for (uint32_t i = 0; i < table_schemas_size; i++) {
        std::string table_name;
        common::SerializationUtil::read_var_str(table_name, in);
        auto table_schema = std::make_shared<TableSchema>();
        table_schema->set_table_name(table_name);
        table_schema->deserialize(in);
        table_schema->set_table_name(table_name);
        table_schemas_.emplace(table_name, std::move(table_schema));
    }

    common::SerializationUtil::read_i64(meta_offset_, in);

    bloom_filter_->deserialize_from(in);

    int32_t tsfile_properties_size = 0;
    common::SerializationUtil::read_var_int(tsfile_properties_size, in);
    for (int i = 0; i < tsfile_properties_size; i++) {
        std::string key, *value;
        common::SerializationUtil::read_var_str(key, in);
        common::SerializationUtil::read_var_char_ptr(value, in);
        tsfile_properties_.emplace(key, value);
    }
    return ret;
}

/* ================ MetaIndexNode ================ */
int MetaIndexNode::binary_search_children(
    std::shared_ptr<IComparable> key, bool exact_search,
    std::shared_ptr<IMetaIndexEntry>& ret_index_entry,
    int64_t& ret_end_offset) {
#if DEBUG_SE
    std::cout << "MetaIndexNode::binary_search_children start, name=" << key
              << ", exact_search=" << exact_search
              << ", children_.size=" << children_.size() << std::endl;
    for (int i = 0; i < (int)children_.size(); i++) {
        std::cout << "Iterating children: " << children_[i]->get_name()
                  << std::endl;
    }
#endif
    bool is_aligned = false;
    if (node_type_ == LEAF_MEASUREMENT && children_.size() == 1 &&
        children_[0]->get_compare_key()->to_string().empty()) {
        is_aligned = true;
    }
    // children_[l] <= name < children_[h]
    int l = -1;
    if (is_aligned) {
        l = 0;
    } else {
        int h = (int)children_.size();
        bool found = false;
        while (l < h - 1) {
            int m = (l + h) / 2;
            int cmp = children_[m]->get_compare_key()->compare(*key);
#if DEBUG_SE
            std::cout
                << "MetaIndexNode::binary_search_children doing, cmp: cur="
                << children_[m]->get_name() << ", name=" << key
                << ", exact_search=" << exact_search
                << ", children_.size=" << children_.size() << std::endl;
#endif
            if (cmp == 0) {
                l = m;
                found = true;
                break;
            } else if (cmp > 0) {  // children_[m] > name
                h = m;
            } else {  // children_[m] < name
                l = m;
            }
        }
        if ((l == -1) || (exact_search && !found)) {
#if DEBUG_SE
            std::cout << "MetaIndexNode::binary_search_children end, "
                         "ret=E_NOT_EXIST, name="
                      << key << ", exact_search=" << exact_search << std::endl;
#endif
            return E_NOT_EXIST;
        }
    }
    ret_index_entry = children_[l]->clone(pa_);
    if (l == (int)children_.size() - 1) {
        ret_end_offset = this->end_offset_;
    } else {
        ret_end_offset = children_[l + 1]->get_offset();
    }
#if DEBUG_SE
    std::cout << "MetaIndexNode::binary_search_children end, ret_index_entry="
              << ret_index_entry << ", ret_end_offset=" << ret_end_offset
              << ", name=" << key << ", exact_search=" << exact_search
              << std::endl;
#endif
    return E_OK;
}

#if 0
int MetaIndexNode::binary_search_children(const String &name,
                                          bool exact_search,
                                          MetaIndexEntry &ret_index_entry,
                                          int64_t &ret_end_offset)
{
  // TODO currently, we do sequence search.
  // We will change it to binary search after replacing SimpleList with SimpleVector
  SimpleList<MetaIndexEntry*>::Iterator it;
  SimpleList<MetaIndexEntry*>::Iterator prev_it;
  SimpleList<MetaIndexEntry*>::Iterator target_it;
  for (it = children_.begin(); it != children_.end(); it++) {
    int cmp_res = it.get()->name_.compare(name);
    if (cmp_res == 0) {
      target_it = it;
      break;
    } else if (cmp_res < 0) {
      prev_it = it;
    } else {
      break;
    }
  } // end for

  if (exact_search && target_it == children_.end()) {
    return E_NOT_EXIST;
  } else {
    if (target_it == children_.end()) {
      target_it = prev_it;
    }
    ret_index_entry = *(target_it.get());
    target_it++;
    if (target_it == children_.end()) {
      ret_end_offset = this->end_offset_;
    } else {
      ret_end_offset = target_it.get()->offset_;
    }
  }
  return E_OK;
}
#endif

}  // end namespace storage