/**
 * 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 <pulsar/defines.h>

#include <cstdint>
#include <iosfwd>
#include <map>
#include <memory>
#include <string>

namespace pulsar {

/**
 *  Encoding types of supported KeyValueSchema for Pulsar messages.
 */
enum class KeyValueEncodingType : uint8_t
{
    /**
     * Key is stored as message key, while value is stored as message payload.
     */
    SEPARATED,

    /**
     * Key and value are stored as message payload.
     */
    INLINE
};

// Return string representation of result code
PULSAR_PUBLIC const char *strEncodingType(pulsar::KeyValueEncodingType encodingType);

PULSAR_PUBLIC KeyValueEncodingType enumEncodingType(const std::string &encodingTypeStr);

enum SchemaType : int8_t
{
    /**
     * No schema defined
     */
    NONE = 0,

    /**
     * Simple String encoding with UTF-8
     */
    STRING = 1,

    /**
     * JSON object encoding and validation
     */
    JSON = 2,

    /**
     * Protobuf message encoding and decoding
     */
    PROTOBUF = 3,

    /**
     * Serialize and deserialize via Avro
     */
    AVRO = 4,

    /**
     * A 8-byte integer.
     */
    INT8 = 6,

    /**
     * A 16-byte integer.
     */
    INT16 = 7,

    /**
     * A 32-byte integer.
     */
    INT32 = 8,

    /**
     * A 64-byte integer.
     */
    INT64 = 9,

    /**
     * A float number.
     */
    FLOAT = 10,

    /**
     * A double number
     */
    DOUBLE = 11,

    /**
     * A Schema that contains Key Schema and Value Schema.
     */
    KEY_VALUE = 15,

    /**
     * Protobuf native schema based on Descriptor.
     */
    PROTOBUF_NATIVE = 20,

    /**
     * A bytes array.
     */
    BYTES = -1,

    /**
     * Auto Consume Type.
     */
    AUTO_CONSUME = -3,

    /**
     * Auto Publish Type.
     */
    AUTO_PUBLISH = -4,
};

// Return string representation of result code
PULSAR_PUBLIC const char *strSchemaType(SchemaType schemaType);

PULSAR_PUBLIC SchemaType enumSchemaType(const std::string &schemaTypeStr);

class SchemaInfoImpl;

typedef std::map<std::string, std::string> StringMap;

/**
 * Encapsulates data around the schema definition
 */
class PULSAR_PUBLIC SchemaInfo {
   public:
    /**
     * The default constructor with following configs:
     * - schemaType: SchemaType::BYTES
     * - name: "BYTES"
     * - schema: ""
     * - properties: {}
     *
     * @see SchemaInfo(SchemaType schemaType, const std::string& name, const std::string& schema, const
     * StringMap& properties)
     */
    SchemaInfo();

    /**
     * @param schemaType the schema type
     * @param name the name of the schema definition
     * @param schema the schema definition as a JSON string
     * @param properties a map of custom defined properties attached to the schema
     */
    SchemaInfo(SchemaType schemaType, const std::string &name, const std::string &schema,
               const StringMap &properties = StringMap());

    /**
     * @param keySchema  the key schema.
     * @param valueSchema  the value schema.
     * @param keyValueEncodingType Encoding types of supported KeyValueSchema for Pulsar messages.
     */
    SchemaInfo(const SchemaInfo &keySchema, const SchemaInfo &valueSchema,
               const KeyValueEncodingType &keyValueEncodingType = KeyValueEncodingType::INLINE);

    /**
     * @return the schema type
     */
    SchemaType getSchemaType() const;

    /**
     * @return the name of the schema definition
     */
    const std::string &getName() const;

    /**
     * @return the schema definition as a JSON string
     */
    const std::string &getSchema() const;

    /**
     * @return a map of custom defined properties attached to the schema
     */
    const StringMap &getProperties() const;

   private:
    typedef std::shared_ptr<SchemaInfoImpl> SchemaInfoImplPtr;
    SchemaInfoImplPtr impl_;
};

}  // namespace pulsar

PULSAR_PUBLIC std::ostream &operator<<(std::ostream &s, pulsar::SchemaType schemaType);

PULSAR_PUBLIC std::ostream &operator<<(std::ostream &s, pulsar::KeyValueEncodingType encodingType);
