#pragma once
#include "record_common.h"
#include "condition.h"
#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/json2ymapsdf/lib/common/config.h>
#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/json2ymapsdf/lib/ymapsdf/schema.h>

namespace maps::wiki::json2ymapsdf::transformers {

const std::string COMMON_FIELD = "COMMON";
const std::string COPY_FIELD = "COPY";
const std::string CONST_FIELD = "CONST";
const std::string AUTO_COPY_FIELD = "AUTO_COPY";
const std::string AUTO_DEFAULT_FIELD = "AUTO_DEFAULT";
const std::string CONDITIONAL_MULTI_FIELD = "CONDITIONAL_MULTI";
const std::string CONDITIONAL_PREFIX = "CONDITIONAL_";

class FieldTransformer {
public:
    virtual ~FieldTransformer() = default;

    virtual void transform(const tds::Item&, ymapsdf::Record& record) const = 0;
    virtual ymapsdf::schema::ColumnSet columns() const = 0;
    virtual std::set<std::string> attributes() const = 0;
    virtual std::string name() const = 0;
    virtual void serialize(maps::json::ObjectBuilder&) const;

    static std::shared_ptr<FieldTransformer>
        create(const ymapsdf::schema::Schema& ymapsdfSchema, const std::string& tblName, const xml3::Node& fieldNode);
};

class SingleFieldTransformer: public FieldTransformer {
public:
    SingleFieldTransformer(
        const ymapsdf::schema::Schema& ymapsdfSchema,
        const std::string& tableName,
        const xml3::Node& fieldNode);
    SingleFieldTransformer(const ymapsdf::schema::Column* column);

    ymapsdf::schema::ColumnSet columns() const override { return {column()}; }

protected:
    const ymapsdf::schema::Column* column() const { return column_; }

private:
    const ymapsdf::schema::Column* column_;
};

class CopyField: public SingleFieldTransformer {
public:
    CopyField(const ymapsdf::schema::Column* column, std::string attrName);
    CopyField(const ymapsdf::schema::Schema& ymapsdfSchema, const std::string& tableName, const xml3::Node& fieldNode);

    void transform(const tds::Item&, ymapsdf::Record& record) const override;
    std::set<std::string> attributes() const override { return {tdsAttrName_}; }

    std::string name() const override { return COPY_FIELD; }

private:
    std::string tdsAttrName_;
};

class AutoCopyField: public CopyField {
public:
    AutoCopyField(const ymapsdf::schema::Column* column, std::string attrName)
        : CopyField(column, std::move(attrName))
    { }

    std::string name() const override { return AUTO_COPY_FIELD; }
};

class ConstField: public SingleFieldTransformer {
public:
    ConstField(const ymapsdf::schema::Column* column, std::string value);
    ConstField(const ymapsdf::schema::Schema& ymapsdfSchema, const std::string& tableName, const xml3::Node& fieldNode);

    void transform(const tds::Item&, ymapsdf::Record& record) const override;

    std::set<std::string> attributes() const override { return {}; }

    std::string name() const override { return CONST_FIELD; }

private:
    std::string value_;
};

class AutoDefaultField: public ConstField {
public:
    explicit AutoDefaultField(const ymapsdf::schema::Column* column)
        : ConstField(column, ymapsdf::VALUE_EMPTY)
    { }

    std::string name() const override { return AUTO_DEFAULT_FIELD; }
};

struct ConditionalTransformer {
    std::shared_ptr<Condition> condition;
    std::shared_ptr<FieldTransformer> transformer;
};

class ConditionalField: public SingleFieldTransformer {
public:
    ConditionalField(const ymapsdf::schema::Schema& ymapsdfSchema, const std::string& tableName, const xml3::Node& fieldNode);
    void transform(const tds::Item&, ymapsdf::Record& record) const override;

    std::set<std::string> attributes() const override;

    std::string name() const override { return name_; }

private:
    std::vector<ConditionalTransformer> conditionalTransformers_;
    std::string name_;
};

} // namespace maps::wiki::json2ymapsdf::transformers
