#include <robot/library/oxygen/indexer/object_context/object_context.h>
#include <robot/library/oxygen/indexer/output/attr_printer/attr_printer.h>

#include <library/cpp/json/json_writer.h>

class TSimpleAttributeMap : public NOxygen::IAttributeMap {
private:
    TString Val;
public:
    explicit TSimpleAttributeMap(const TString& val)
        : Val(val)
    {
    }

    bool HasAttr(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        return true;
    }
    i8 AttrAsI8(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    i16 AttrAsI16(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    i32 AttrAsI32(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    i64 AttrAsI64(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    ui8 AttrAsUi8(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    ui16 AttrAsUi16(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    ui32 AttrAsUi32(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    ui64 AttrAsUi64(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    TString AttrAsString(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        return Val;
    }
    bool AttrAsBool(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    float AttrAsFloat(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
    double AttrAsDouble(TStringBuf attrName) const override {
        Y_UNUSED(attrName);
        Y_ENSURE(false, "Not implemented.");
    }
};

TString ProcessTuple(const TString& label, const TString& data) {
    if (data.empty())
        return data;

    static THashMap<TString, NOxygen::EOxygenAttrType> label2AttrType =
    {
        {"Arc", NOxygen::EOxygenAttrType::OAT_TarcView},
        {"refarc", NOxygen::EOxygenAttrType::OAT_TarcView},
        {"LinkAnnArc", NOxygen::EOxygenAttrType::OAT_TarcView},
        {"UrlDataErf2Features", NOxygen::EOxygenAttrType::OAT_DocErf2InfoProto},
        {"HostErfInfo", NOxygen::EOxygenAttrType::OAT_Herf},
        {"RegHostErfInfo", NOxygen::EOxygenAttrType::OAT_RegHerfInfo}

    };
    static NOxygen::TOxygenPrinters printers;
    static auto dumpFactory = printers.GetFactory(NOxygen::EPrinterFormat::PF_Dump);
    if (label2AttrType.contains(label)) {
        try {
            auto attrMap = TSimpleAttributeMap(data);
            return dumpFactory.GetAttrPrinterByType(label2AttrType.at(label))->Print(attrMap, label);
        } catch (const std::exception& e) {
            Cerr << "ERROR: cannot decode tuple label=" << label << ": " << e.what();
            return data;
        }
    }
    return data;
}

NJson::TJsonValue KiwiObjectToJson(const NKiwi::TKiwiObject& kiwiObject) {
    NJson::TJsonValue value(NJson::JSON_MAP);
    for (auto it = kiwiObject.GetIterator(); it.IsValid(); it.Advance()) {
        auto current = it.Current();
        value[current->GetLabel()] = ProcessTuple(current->GetLabel(), TString{current->AsStringBuf()});
    }
    return value;
}

NJson::TJsonValue DeserializeKiwiObjectToJson(const TBlob& data) {
    NKiwi::TKiwiObject kiwi(data.AsCharPtr(), data.Size());
    return KiwiObjectToJson(kiwi);
}
