/*
 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
 *
 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
 *
*/

#include <libyang-cpp/Enum.hpp>
#include <libyang-cpp/Utils.hpp>
#include <string_view>
#include "UniqueResource.hpp"
#include "utils.hpp"
#include "yang_schema.hpp"

class YangLoadError : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
    ~YangLoadError() override = default;
};

class UnsupportedYangTypeException : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
    ~UnsupportedYangTypeException() override = default;
};

class InvalidSchemaQueryException : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
    ~InvalidSchemaQueryException() override = default;
};

YangSchema::YangSchema()
    : m_context(std::nullopt, libyang::ContextOptions::DisableSearchDirs | libyang::ContextOptions::SetPrivParsed)
{
}

YangSchema::YangSchema(libyang::Context lyCtx)
    : m_context(lyCtx)
{
}

YangSchema::~YangSchema() = default;

void YangSchema::addSchemaString(const char* schema)
{
    m_context.parseModule(std::string{schema}, libyang::SchemaFormat::YANG);
}

void YangSchema::addSchemaDirectory(const char* directoryName)
{
    m_context.setSearchDir(directoryName);
}

void YangSchema::addSchemaFile(const char* filename)
{
    m_context.parseModule(std::filesystem::path{filename}, libyang::SchemaFormat::YANG);
}

bool YangSchema::isModule(const std::string& name) const
{
    return m_context.getModuleImplemented(name).has_value();
}

bool YangSchema::listHasKey(const schemaPath_& listPath, const std::string& key) const
{
    const auto keys = listKeys(listPath);
    return keys.find(key) != keys.end();
}

bool YangSchema::leafIsKey(const std::string& leafPath) const
{
    auto node = getSchemaNode(leafPath);
    if (!node || node->nodeType() != libyang::NodeType::Leaf) {
        return false;
    }

    return node->asLeaf().isKey();
}

std::optional<libyang::SchemaNode> YangSchema::impl_getSchemaNode(const std::string& node) const
{
    // libyang::Context::findPath throws an exception, when no matching schema node is found. This exception has the
    // ValidationFailure error code. We will catch that exception (and rethrow if it's not the correct error code.
    //
    // Also, we need to use findPath twice if we're trying to find output nodes.
    try {
        return m_context.findPath(node);
    } catch (libyang::ErrorWithCode& err) {
        if (err.code() != libyang::ErrorCode::ValidationFailure) {
            throw;
        }
    }
    try {
        return m_context.findPath(node, libyang::OutputNodes::Yes);
    } catch (libyang::ErrorWithCode& err) {
        if (err.code() != libyang::ErrorCode::ValidationFailure) {
            throw;
        }
    }

    // We didn't find a matching node.
    return std::nullopt;
}


std::optional<libyang::SchemaNode> YangSchema::getSchemaNode(const std::string& node) const
{
    return impl_getSchemaNode(node);
}

std::optional<libyang::SchemaNode> YangSchema::getSchemaNode(const schemaPath_& location, const ModuleNodePair& node) const
{
    std::string absPath = joinPaths(pathToSchemaString(location, Prefixes::Always), fullNodeName(location, node));

    return impl_getSchemaNode(absPath);
}

std::optional<libyang::SchemaNode> YangSchema::getSchemaNode(const schemaPath_& listPath) const
{
    std::string absPath = pathToSchemaString(listPath, Prefixes::Always);
    return impl_getSchemaNode(absPath);
}

const std::set<std::string> YangSchema::listKeys(const schemaPath_& listPath) const
{
    auto node = getSchemaNode(listPath);
    if (node->nodeType() != libyang::NodeType::List) {
        return {};
    }

    std::set<std::string> keys;
    auto keysVec = node->asList().keys();

    std::transform(keysVec.begin(), keysVec.end(), std::inserter(keys, keys.begin()), [](const auto& it) { return std::string{it.name()}; });
    return keys;
}

std::set<enum_> enumValues(const libyang::types::Type& type)
{
    auto enums = type.asEnum().items();
    std::set<enum_> enumSet;
    std::transform(enums.begin(), enums.end(), std::inserter(enumSet, enumSet.end()), [](auto it) { return enum_{std::string{it.name}}; });
    return enumSet;
}

std::set<identityRef_> validIdentities(const libyang::types::Type& type)
{
    std::set<identityRef_> identSet;

    std::function<void(const std::vector<libyang::Identity>&)> impl = [&identSet, &impl] (const std::vector<libyang::Identity>& idents) {
        if (idents.empty()) {
            return;
        }

        for (const auto& ident : idents) {
            identSet.emplace(std::string{ident.module().name()}, std::string{ident.name()});
            impl(ident.derived());
        }
    };

    for (const auto& base : type.asIdentityRef().bases()) {
        impl(base.derived());
    }

    return identSet;
}

std::string leafrefPath(const libyang::types::Type& type)
{
    return std::string{type.asLeafRef().path()};
}

template <typename NodeType>
yang::TypeInfo YangSchema::impl_leafType(const NodeType& node) const
{
    using namespace std::string_literals;
    auto leaf = std::make_shared<NodeType>(node);
    auto leafUnits = leaf->units();
    std::function<yang::TypeInfo(const libyang::types::Type&)> resolveType;
    resolveType = [&resolveType, leaf, leafUnits](const libyang::types::Type& type) -> yang::TypeInfo {
        yang::LeafDataType resType;
        switch (type.base()) {
        case libyang::LeafBaseType::String:
            resType.emplace<yang::String>();
            break;
        case libyang::LeafBaseType::Dec64:
            resType.emplace<yang::Decimal>();
            break;
        case libyang::LeafBaseType::Bool:
            resType.emplace<yang::Bool>();
            break;
        case libyang::LeafBaseType::Int8:
            resType.emplace<yang::Int8>();
            break;
        case libyang::LeafBaseType::Int16:
            resType.emplace<yang::Int16>();
            break;
        case libyang::LeafBaseType::Int32:
            resType.emplace<yang::Int32>();
            break;
        case libyang::LeafBaseType::Int64:
            resType.emplace<yang::Int64>();
            break;
        case libyang::LeafBaseType::Uint8:
            resType.emplace<yang::Uint8>();
            break;
        case libyang::LeafBaseType::Uint16:
            resType.emplace<yang::Uint16>();
            break;
        case libyang::LeafBaseType::Uint32:
            resType.emplace<yang::Uint32>();
            break;
        case libyang::LeafBaseType::Uint64:
            resType.emplace<yang::Uint64>();
            break;
        case libyang::LeafBaseType::Binary:
            resType.emplace<yang::Binary>();
            break;
        case libyang::LeafBaseType::Empty:
            resType.emplace<yang::Empty>();
            break;
        case libyang::LeafBaseType::Enum:
            resType.emplace<yang::Enum>(enumValues(type));
            break;
        case libyang::LeafBaseType::IdentityRef:
            resType.emplace<yang::IdentityRef>(validIdentities(type));
            break;
        case libyang::LeafBaseType::Leafref:
            resType.emplace<yang::LeafRef>(::leafrefPath(type), std::make_unique<yang::TypeInfo>(resolveType(type.asLeafRef().resolvedType())));
            break;
        case libyang::LeafBaseType::Bits: {
            auto resBits = yang::Bits{};
            for (const auto& bit : type.asBits().items()) {
                resBits.m_allowedValues.emplace(std::string{bit.name});
            }
            resType.emplace<yang::Bits>(std::move(resBits));
            break;
        }
        case libyang::LeafBaseType::Union: {
            auto resUnion = yang::Union{};
            for (auto unionType : type.asUnion().types()) {
                resUnion.m_unionTypes.emplace_back(resolveType(unionType));
            }
            resType.emplace<yang::Union>(std::move(resUnion));
            break;
        }
        case libyang::LeafBaseType::InstanceIdentifier: {
            resType.emplace<yang::InstanceIdentifier>();
            break;
        }
        default:
            using namespace std::string_literals;
            throw UnsupportedYangTypeException("the type of "s +
                    std::string{leaf->name()} +
                    " is not supported: " +
                    std::to_string(std::underlying_type_t<libyang::LeafBaseType>(leaf->valueType().base())));
        }
        // note https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109434
        std::optional<std::string> typeDesc;

        try {
            typeDesc = type.description();
        } catch (libyang::ParsedInfoUnavailable&) {
            // libyang context doesn't have the parsed info.
        }

        return yang::TypeInfo(resType, std::optional<std::string>{leafUnits}, typeDesc);
    };
    return resolveType(leaf->valueType());
}

yang::TypeInfo YangSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
{
    auto lyNode = getSchemaNode(location, node);
    switch (lyNode->nodeType()) {
    case libyang::NodeType::Leaf:
        return impl_leafType(lyNode->asLeaf());
    case libyang::NodeType::Leaflist:
        return impl_leafType(lyNode->asLeafList());
    default:
        throw std::logic_error("YangSchema::leafType: type must be leaf or leaflist");
    }
}

yang::TypeInfo YangSchema::leafType(const std::string& path) const
{
    auto lyNode = getSchemaNode(path);
    switch (lyNode->nodeType()) {
    case libyang::NodeType::Leaf:
        return impl_leafType(lyNode->asLeaf());
    case libyang::NodeType::Leaflist:
        return impl_leafType(lyNode->asLeafList());
    default:
        throw std::logic_error("YangSchema::leafType: type must be leaf or leaflist");
    }
}

std::optional<std::string> YangSchema::leafTypeName(const std::string& path) const
{
    auto leaf = getSchemaNode(path)->asLeaf();
    try {
        return std::string{leaf.valueType().name()};
    } catch (libyang::ParsedInfoUnavailable&) {
        return std::nullopt;
    }
}

std::string YangSchema::leafrefPath(const std::string& leafrefPath) const
{
    using namespace std::string_literals;
    return ::leafrefPath(getSchemaNode(leafrefPath)->asLeaf().valueType());
}

std::set<std::string> YangSchema::modules() const
{
    const auto& modules = m_context.modules();

    std::set<std::string> res;
    std::transform(modules.begin(), modules.end(), std::inserter(res, res.end()), [](const auto module) { return std::string{module.name()}; });
    return res;
}

std::set<ModuleNodePair> YangSchema::availableNodes(const boost::variant<dataPath_, schemaPath_, module_>& path, const Recursion recursion) const
{
    using namespace std::string_view_literals;
    std::set<ModuleNodePair> res;
    std::vector<libyang::ChildInstanstiables> nodeCollections;
    std::string topLevelModule;

    if (path.type() == typeid(module_)) {
        nodeCollections.emplace_back(m_context.getModule(boost::get<module_>(path).m_name)->childInstantiables());
    } else {
        auto schemaPath = anyPathToSchemaPath(path);
        if (schemaPath.m_nodes.empty()) {
            for (const auto& module : m_context.modules()) {
                if (module.implemented()) {
                    nodeCollections.emplace_back(module.childInstantiables());
                }
            }
        } else {
            const auto pathString = pathToSchemaString(schemaPath, Prefixes::Always);
            const auto node = getSchemaNode(pathString);
            nodeCollections.emplace_back(node->childInstantiables());
            topLevelModule = schemaPath.m_nodes.begin()->m_prefix->m_name;
        }
    }

    for (const auto& coll : nodeCollections) {
        for (const auto& node : coll) {
            if (node.module().name() == "ietf-yang-library"sv) {
                continue;
            }

            if (node.module().name() == "ietf-yang-schema-mount"sv) {
                continue;
            }

            if (recursion == Recursion::Recursive) {
                for (auto it : node.childrenDfs()) {
                    res.insert(ModuleNodePair(boost::none, it.path()));
                }
            } else {
                ModuleNodePair toInsert;
                if (topLevelModule.empty() || topLevelModule != node.module().name()) {
                    toInsert.first = std::string{node.module().name()};
                }
                toInsert.second = node.name();
                res.insert(toInsert);
            }
        }
    }

    return res;
}

void YangSchema::loadModule(const std::string& moduleName)
{
    m_context.loadModule(moduleName);
}

void YangSchema::setEnabledFeatures(const std::string& moduleName, const std::vector<std::string>& features)
{
    using namespace std::string_literals;
    auto module = getYangModule(moduleName);
    if (!module) {
        throw std::runtime_error("Module \""s + moduleName + "\" doesn't exist.");
    }
    try {
        module->setImplemented(features);
    } catch (libyang::ErrorWithCode&) {
        throw std::runtime_error("Can't enable features for module \"" + moduleName + "\".");
    }
}

void YangSchema::registerModuleCallback(const std::function<std::string(const std::string_view, const std::optional<std::string_view>, const std::optional<std::string_view>, const std::optional<std::string_view>)>& clb)
{
    auto lambda = [clb](const auto mod_name, const auto mod_revision, const auto submod_name, const auto submod_revision) -> std::optional<libyang::ModuleInfo> {
        (void)submod_revision;
        auto moduleSource = clb(mod_name, mod_revision, submod_name, submod_revision);
        if (moduleSource.empty()) {
            return std::nullopt;
        }
        return libyang::ModuleInfo {
            .data = moduleSource,
            .format = libyang::SchemaFormat::YANG

        };
    };

    m_context.registerModuleCallback(lambda);
}

libyang::CreatedNodes YangSchema::dataNodeFromPath(const std::string& path, const std::optional<const std::string> value) const
{
    auto options = [this, &path, &value] {
        // If we're creating a node without a value and it's not the "empty" type, then we also need the Opaque flag.
        auto schema = getSchemaNode(path);
        if (schema->nodeType() == libyang::NodeType::Leaf &&
            schema->asLeaf().valueType().base() != libyang::LeafBaseType::Empty &&
            !value) {
            return std::optional<libyang::CreationOptions>{libyang::CreationOptions::Opaque};
        }

        return std::optional<libyang::CreationOptions>{};
    }();
    return m_context.newPath2(path, value, options);
}

std::optional<libyang::Module> YangSchema::getYangModule(const std::string& name)
{
    return m_context.getModuleImplemented(name);
}

namespace {
yang::NodeTypes impl_nodeType(const libyang::SchemaNode& node)
{
    switch (node.nodeType()) {
    case libyang::NodeType::Container:
        return node.asContainer().isPresence() ? yang::NodeTypes::PresenceContainer : yang::NodeTypes::Container;
    case libyang::NodeType::Leaf:
        return yang::NodeTypes::Leaf;
    case libyang::NodeType::List:
        return yang::NodeTypes::List;
    case libyang::NodeType::RPC:
        return yang::NodeTypes::Rpc;
    case libyang::NodeType::Action:
        return yang::NodeTypes::Action;
    case libyang::NodeType::Notification:
        return yang::NodeTypes::Notification;
    case libyang::NodeType::AnyXML:
        return yang::NodeTypes::AnyXml;
    case libyang::NodeType::Leaflist:
        return yang::NodeTypes::LeafList;
    default:
        throw InvalidNodeException(); // FIXME: Implement all types.
    }
}
}

yang::NodeTypes YangSchema::nodeType(const schemaPath_& location, const ModuleNodePair& node) const
{
    return impl_nodeType(*getSchemaNode(location, node));
}

yang::NodeTypes YangSchema::nodeType(const std::string& path) const
{
    return impl_nodeType(*getSchemaNode(path));
}

std::optional<std::string> YangSchema::description(const std::string& path) const
{
    auto desc = getSchemaNode(path.c_str())->description();
    return desc ? std::optional<std::string>{desc} : std::nullopt;

}

yang::Status YangSchema::status(const std::string& location) const
{
    auto node = getSchemaNode(location.c_str());
    switch (node->status()) {
    case libyang::Status::Deprecated:
        return yang::Status::Deprecated;
    case libyang::Status::Obsolete:
        return yang::Status::Obsolete;
    case libyang::Status::Current:
        return yang::Status::Current;
    }

    __builtin_unreachable();
}

bool YangSchema::hasInputNodes(const std::string& path) const
{
    auto node = getSchemaNode(path.c_str());
    if (auto type = node->nodeType(); type != libyang::NodeType::Action && type != libyang::NodeType::RPC) {
        throw std::logic_error("StaticSchema::hasInputNodes called with non-RPC/action path");
    }

    // The first child gives the /input node and then I check whether it has a child.
    return node->child()->child().has_value();
}

bool YangSchema::isConfig(const std::string& path) const
{
    auto node = getSchemaNode(path.c_str());
    if (node->isInput()) {
        return true;
    }

    try {
        if (node->config() == libyang::Config::True) {
            return true;
        }
    } catch (libyang::Error&) {
        // For non-data nodes (like `rpc`), the config value can't be retrieved. In this case, we'll just default to
        // "false".
    }

    return false;
}

std::optional<std::string> YangSchema::defaultValue(const std::string& leafPath) const
{
    return std::optional<std::string>{getSchemaNode(leafPath)->asLeaf().defaultValueStr()};
}

std::string YangSchema::dataPathToSchemaPath(const std::string& path)
{
    return std::string{getSchemaNode(path)->path()};
}
