/*
 * 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.
 */

#pragma once

#include <cassert>
#include <cstdint>
#include <cstring>
#include <memory>
#include <type_traits>

#include "fmt/format.h"
#include "paimon/common/memory/memory_slice.h"
#include "paimon/common/utils/math.h"
#include "paimon/common/utils/var_length_int_utils.h"
#include "paimon/io/byte_order.h"
#include "paimon/status.h"
#include "paimon/visibility.h"
namespace paimon {
class MemoryPool;

///  Input stream over a MemorySlice with inline hot-path methods.
class PAIMON_EXPORT MemorySliceInput {
 public:
    explicit MemorySliceInput(const MemorySlice& slice)
        : slice_(slice), data_(slice.Data()), length_(slice.Length()) {}

    inline int32_t Position() const {
        return position_;
    }

    inline Status SetPosition(int32_t position) {
        if (position < 0 || position > length_) {
            return Status::IndexError(fmt::format("position {} index out of bounds", position));
        }
        position_ = position;
        return Status::OK();
    }

    inline bool IsReadable() const {
        return position_ < length_;
    }

    inline int32_t Available() const {
        return length_ - position_;
    }

    inline int8_t ReadByte() {
        int8_t value;
        std::memcpy(&value, data_ + position_, 1);
        position_++;
        return value;
    }

    inline int8_t ReadUnsignedByte() {
        return static_cast<int8_t>(static_cast<uint8_t>(data_[position_++]));
    }

    inline int32_t ReadInt() {
        int32_t v;
        std::memcpy(&v, data_ + position_, sizeof(v));
        position_ += 4;
        if (NeedSwap()) {
            return EndianSwapValue(v);
        }
        return v;
    }

    inline int64_t ReadLong() {
        int64_t v;
        std::memcpy(&v, data_ + position_, sizeof(v));
        position_ += 8;
        if (NeedSwap()) {
            return EndianSwapValue(v);
        }
        return v;
    }

    /// Reads a varint32 from the current position.
    inline Result<int32_t> ReadVarLenInt() {
        return VarLengthIntUtils::DecodeInt(data_, &position_);
    }

    /// Reads a varint64 from the current position.
    inline Result<int64_t> ReadVarLenLong() {
        return VarLengthIntUtils::DecodeLong(data_, &position_);
    }

    inline MemorySlice ReadSliceView(int32_t length) {
        auto view_segment = MemorySegment::WrapView(data_ + position_, length);
        position_ += length;
        return MemorySlice(view_segment, 0, length);
    }

    void SetOrder(ByteOrder order) {
        byte_order_ = order;
    }

 private:
    inline bool NeedSwap() const {
        return SystemByteOrder() != byte_order_;
    }

 private:
    MemorySlice slice_;
    const char* data_;  // Cached raw pointer for fast access.
    int32_t length_;    // Cached length.
    int32_t position_ = 0;

    ByteOrder byte_order_ = SystemByteOrder();
};

}  // namespace paimon
