/*
 * 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 "paimon/data/blob.h"

#include <memory>
#include <utility>

#include "arrow/c/bridge.h"
#include "paimon/common/data/blob_descriptor.h"
#include "paimon/common/data/blob_utils.h"
#include "paimon/common/io/offset_input_stream.h"
#include "paimon/common/utils/arrow/status_utils.h"
#include "paimon/common/utils/path_util.h"
#include "paimon/common/utils/stream_utils.h"
#include "paimon/memory/bytes.h"
#include "paimon/status.h"

namespace paimon {

class MemoryPool;

class Blob::Impl {
 public:
    explicit Impl(std::unique_ptr<BlobDescriptor>&& descriptor)
        : descriptor_(std::move(descriptor)) {}

    PAIMON_UNIQUE_PTR<Bytes> SerializeDescriptor(const std::shared_ptr<MemoryPool>& pool) const {
        return descriptor_->Serialize(pool);
    }

    const BlobDescriptor* GetDescriptor() const {
        return descriptor_.get();
    }

    const std::string& Uri() const {
        return descriptor_->Uri();
    }

 private:
    std::unique_ptr<BlobDescriptor> descriptor_;
};

Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path) {
    return FromPath(path, /*offset=*/0, /*length=*/-1);
}

Result<std::unique_ptr<Blob>> Blob::FromPath(const std::string& path, int64_t offset,
                                             int64_t length) {
    PAIMON_ASSIGN_OR_RAISE(std::string normalized_path, PathUtil::NormalizePath(path));
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<BlobDescriptor> descriptor,
                           BlobDescriptor::Create(normalized_path, offset, length));
    auto impl = std::make_unique<Impl>(std::move(descriptor));
    return std::unique_ptr<Blob>(new Blob(std::move(impl)));
}

Blob::Blob(std::unique_ptr<Impl>&& impl) : impl_(std::move(impl)) {}
Blob::~Blob() = default;

Result<std::unique_ptr<Blob>> Blob::FromDescriptor(const char* buffer, uint64_t length) {
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<BlobDescriptor> descriptor,
                           BlobDescriptor::Deserialize(buffer, length));

    auto impl = std::make_unique<Impl>(std::move(descriptor));
    return std::unique_ptr<Blob>(new Blob(std::move(impl)));
}

PAIMON_UNIQUE_PTR<Bytes> Blob::ToDescriptor(const std::shared_ptr<MemoryPool>& pool) const {
    return impl_->SerializeDescriptor(pool);
}

const std::string& Blob::Uri() const {
    return impl_->Uri();
}

Result<std::unique_ptr<InputStream>> Blob::NewInputStream(
    const std::shared_ptr<FileSystem>& fs) const {
    if (fs == nullptr) {
        return Status::Invalid("file system is nullptr");
    }
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<InputStream> file,
                           fs->Open(impl_->GetDescriptor()->Uri()));

    int64_t blob_length = impl_->GetDescriptor()->Length();
    int64_t blob_offset = impl_->GetDescriptor()->Offset();

    PAIMON_ASSIGN_OR_RAISE(int64_t total_length, file->Length());
    if (PAIMON_UNLIKELY(blob_offset > total_length)) {
        return Status::Invalid(
            fmt::format("offset {} exceed total length {}", blob_offset, total_length));
    }
    if (blob_length == -1) {
        // blob_length == -1 means it's dynamic length, should read to the end
        blob_length = total_length - blob_offset;
    }

    return OffsetInputStream::Create(std::move(file), blob_length, blob_offset, total_length);
}

Result<PAIMON_UNIQUE_PTR<Bytes>> Blob::ToData(const std::shared_ptr<FileSystem>& fs,
                                              const std::shared_ptr<MemoryPool>& pool) const {
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<InputStream> input_stream, NewInputStream(fs));
    return StreamUtils::ReadAsyncFully(std::move(input_stream), pool);
}

Result<std::unique_ptr<ArrowSchema>> Blob::ArrowField(
    const std::string& field_name, bool nullable,
    std::unordered_map<std::string, std::string> metadata) {
    auto blob_field = BlobUtils::ToArrowField(field_name, nullable, metadata);
    auto field = std::make_unique<::ArrowSchema>();
    PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportField(*blob_field, field.get()));
    return field;
}

}  // namespace paimon
