#include "lightning_walker.h"
#include "tree.h"
#include <algorithm>
#include <cstring>

namespace cutysoup {

LightningWalker::LightningWalker(const Config& config) 
    : config_(config) {
}

std::shared_ptr<Node> LightningWalker::create_node(GumboNode* gumbo_node, const Tree* tree) const {
    if (!gumbo_node || !tree) return nullptr;
    return tree->get_or_create_node(gumbo_node);
}

std::vector<std::shared_ptr<Node>> LightningWalker::create_nodes_batch(
    const std::vector<GumboNode*>& gumbo_nodes,
    const Tree* tree
) const {
    std::vector<std::shared_ptr<Node>> nodes;
    nodes.reserve(gumbo_nodes.size());
    
    for (GumboNode* gumbo_node : gumbo_nodes) {
        if (gumbo_node) {
            nodes.emplace_back(tree->get_or_create_node(gumbo_node));
        }
    }
    
    return nodes;
}

inline const char* LightningWalker::get_attribute_value_fast(const GumboVector* attrs, const char* name) {
    if (!attrs || !name) return nullptr;
    
    // Manual loop unrolling for common case (few attributes)
    const unsigned int len = attrs->length;
    GumboAttribute** data = reinterpret_cast<GumboAttribute**>(attrs->data);
    
    for (unsigned int i = 0; i < len; ++i) {
        GumboAttribute* attr = data[i];
        if (attr && attr->name && strcmp(attr->name, name) == 0) {
            return attr->value;
        }
    }
    
    return nullptr;
}

inline bool LightningWalker::has_class_name_fast(const char* class_attr, const char* target, size_t target_len) {
    if (!class_attr || !target || target_len == 0) return false;
    
    const char* pos = class_attr;
    const char* end = class_attr + strlen(class_attr);
    
    while (pos < end) {
        // Skip whitespace
        while (pos < end && (*pos == ' ' || *pos == '\t' || *pos == '\n' || *pos == '\r')) {
            ++pos;
        }
        
        if (pos >= end) break;
        
        // Find end of current class
        const char* class_start = pos;
        while (pos < end && *pos != ' ' && *pos != '\t' && *pos != '\n' && *pos != '\r') {
            ++pos;
        }
        
        const size_t current_len = pos - class_start;
        
        // Quick length check + memcmp
        if (current_len == target_len && memcmp(class_start, target, target_len) == 0) {
            return true;
        }
    }
    
    return false;
}

std::vector<std::shared_ptr<Node>> LightningWalker::find_by_tag_lightning(
    GumboNode* root,
    const Tree* tree,
    const std::string& tag_name
) {
    if (!root) return {};
    
    // Convert to enum for ultra-fast comparison
    GumboTag target_tag = gumbo_tag_enum(tag_name.c_str());
    
    std::vector<GumboNode*> raw_results;
    raw_results.reserve(config_.reserve_capacity);
    
    if (target_tag != GUMBO_TAG_UNKNOWN) {
        // Ultra-fast enum-based search
        collect_elements_by_tag(root, target_tag, raw_results);
    } else {
        // Fallback for custom tags
        const char* tag_cstr = tag_name.c_str();
        const size_t tag_len = tag_name.length();
        
        traverse_linear(root, [&](GumboNode* node) {
            if (node && node->type == GUMBO_NODE_ELEMENT) {
                const char* node_name = gumbo_normalized_tagname(node->v.element.tag);
                if (node_name && strlen(node_name) == tag_len && 
                    memcmp(node_name, tag_cstr, tag_len) == 0) {
                    raw_results.push_back(node);
                }
            }
        });
    }
    
    // Convert to Node objects in one batch
    return create_nodes_batch(raw_results, tree);
}

std::vector<std::shared_ptr<Node>> LightningWalker::find_by_class_lightning(
    GumboNode* root,
    const Tree* tree,
    const std::string& class_name
) {
    if (!root) return {};
    
    std::vector<GumboNode*> raw_results;
    raw_results.reserve(config_.reserve_capacity);
    
    collect_elements_by_class(root, class_name.c_str(), class_name.length(), raw_results);
    
    return create_nodes_batch(raw_results, tree);
}

std::shared_ptr<Node> LightningWalker::find_by_id_lightning(
    GumboNode* root,
    const Tree* tree,
    const std::string& id
) {
    if (!root) return nullptr;
    
    const char* id_cstr = id.c_str();
    const size_t id_len = id.length();
    
    GumboNode* found = nullptr;
    
    traverse_linear(root, [&](GumboNode* node) {
        if (found) return;  // Early termination
        
        if (node && node->type == GUMBO_NODE_ELEMENT) {
            const char* node_id = get_attribute_value_fast(&node->v.element.attributes, "id");
            if (node_id && strlen(node_id) == id_len && 
                memcmp(node_id, id_cstr, id_len) == 0) {
                found = node;
            }
        }
    });
    
    return found ? create_node(found, tree) : nullptr;
}

void LightningWalker::collect_elements_by_tag(
    GumboNode* root,
    GumboTag target_tag,
    std::vector<GumboNode*>& results
) {
    if (!root) return;
    
    traverse_linear(root, [&](GumboNode* node) {
        if (node && node->type == GUMBO_NODE_ELEMENT && node->v.element.tag == target_tag) {
            results.push_back(node);
        }
    });
}

void LightningWalker::collect_elements_by_class(
    GumboNode* root,
    const char* class_name,
    size_t class_len,
    std::vector<GumboNode*>& results
) {
    if (!root || !class_name) return;
    
    traverse_linear(root, [&](GumboNode* node) {
        if (node && node->type == GUMBO_NODE_ELEMENT) {
            const char* class_attr = get_attribute_value_fast(&node->v.element.attributes, "class");
            if (class_attr && has_class_name_fast(class_attr, class_name, class_len)) {
                results.push_back(node);
            }
        }
    });
}

} // namespace cutysoup
