#pragma once

#include <vector>
#include <string>
#include <memory>
#include <cstring>
#include <type_traits>
#include "gumbo.h"
#include "node.h"

#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
#include <immintrin.h>
#define CUTYSOUP_HAS_X86_SIMD 1
#else
#define CUTYSOUP_HAS_X86_SIMD 0
#endif

namespace cutysoup {

// Forward declarations
class Tree;
class Node;

/**
 * Ultra-fast sequential tree walker with SIMD optimizations
 * 
 * Design philosophy:
 * - Zero overhead for typical web scraping workloads (< 100k nodes)
 * - SIMD-optimized string comparisons  
 * - Cache-friendly memory access patterns
 * - Minimal memory allocations
 * - Optimized for common search patterns
 */
class UltraFastWalker {
public:
    struct Config {
        bool enable_simd;
        bool enable_branch_prediction_hints;
        size_t reserve_capacity;  // Pre-allocate result vectors
        
        Config() : enable_simd(CUTYSOUP_HAS_X86_SIMD != 0), enable_branch_prediction_hints(true), reserve_capacity(64) {}
    };
    
    explicit UltraFastWalker(const Config& config = Config());
    
    // Ultra-fast specialized searches
    std::vector<std::shared_ptr<Node>> find_by_tag_ultra_fast(
        GumboNode* root,
        const Tree* tree,
        const std::string& tag_name
    );
    
    std::vector<std::shared_ptr<Node>> find_by_class_ultra_fast(
        GumboNode* root,
        const Tree* tree,
        const std::string& class_name
    );
    
    std::shared_ptr<Node> find_by_id_ultra_fast(
        GumboNode* root,
        const Tree* tree,
        const std::string& id
    );
    
    // SIMD-optimized string matching
    std::vector<std::shared_ptr<Node>> find_by_tag_simd(
        GumboNode* root,
        const Tree* tree,
        const char* tag_name,
        size_t tag_len
    );
    
    // High-performance generic search with compile-time optimizations
    template<typename Predicate>
    std::vector<std::shared_ptr<Node>> find_all_optimized(
        GumboNode* root,
        const Tree* tree,
        Predicate predicate
    );
    
    template<typename Predicate>
    std::shared_ptr<Node> find_optimized(
        GumboNode* root,
        const Tree* tree,
        Predicate predicate
    );
    
    // Cache-friendly bulk operations
    void collect_all_elements_fast(
        GumboNode* root,
        std::vector<GumboNode*>& out_elements
    );
    
    void collect_all_elements_with_tag_fast(
        GumboNode* root,
        GumboTag target_tag,
        std::vector<GumboNode*>& out_elements
    );
    
private:
    Config config_;
    
    // SIMD helper functions
    bool simd_string_equals(const char* str1, const char* str2, size_t len) const;
    bool simd_contains_class(const char* class_attr, const char* target_class, 
                           size_t attr_len, size_t target_len) const;
    
    // Optimized attribute searching
    const char* find_attribute_fast(const GumboVector* attributes, const char* attr_name) const;
    bool has_class_fast(const GumboVector* attributes, const char* class_name, size_t class_len) const;
    
    // Cache-friendly tree traversal
    template<typename Func>
    void traverse_depth_first_optimized(GumboNode* root, Func func);
    
    // Utility functions
    std::shared_ptr<Node> create_node_fast(GumboNode* gumbo_node, const Tree* tree) const;
    
    // Branch prediction hints (cross-platform)
    static constexpr bool likely(bool condition) {
#ifdef __GNUC__
        return __builtin_expect(condition, 1);
#else
        return condition;
#endif
    }
    
    static constexpr bool unlikely(bool condition) {
#ifdef __GNUC__
        return __builtin_expect(condition, 0);
#else
        return condition;
#endif
    }
};

// Template implementations

template<typename Predicate>
std::vector<std::shared_ptr<Node>> UltraFastWalker::find_all_optimized(
    GumboNode* root,
    const Tree* tree,
    Predicate predicate
) {
    std::vector<std::shared_ptr<Node>> results;
    results.reserve(config_.reserve_capacity);
    
    if (unlikely(!root)) return results;
    
    traverse_depth_first_optimized(root, [&](GumboNode* node) {
        if (likely(node && predicate(node))) {
            results.emplace_back(create_node_fast(node, tree));
        }
    });
    
    return results;
}

template<typename Predicate>
std::shared_ptr<Node> UltraFastWalker::find_optimized(
    GumboNode* root,
    const Tree* tree,
    Predicate predicate
) {
    if (unlikely(!root)) return nullptr;
    
    std::shared_ptr<Node> result;
    
    traverse_depth_first_optimized(root, [&](GumboNode* node) -> bool {
        if (likely(node && predicate(node))) {
            result = create_node_fast(node, tree);
            return false;  // Early termination
        }
        return true;  // Continue
    });
    
    return result;
}

template<typename Func>
void UltraFastWalker::traverse_depth_first_optimized(GumboNode* root, Func func) {
    if (unlikely(!root)) return;
    
    // Use a stack-based approach to avoid recursion overhead
    // Pre-allocate stack capacity for typical document depths
    std::vector<GumboNode*> stack;
    stack.reserve(64);
    stack.push_back(root);
    
    while (likely(!stack.empty())) {
        GumboNode* current = stack.back();
        stack.pop_back();
        
        if (unlikely(!current)) continue;
        
        // Process current node - check if Func returns bool for early termination
        if constexpr (std::is_same_v<std::invoke_result_t<Func, GumboNode*>, bool>) {
            if (!func(current)) {
                return;  // Early termination requested
            }
        } else {
            func(current);
        }
        
        // Add children to stack in reverse order for depth-first traversal
        if (likely(current->type == GUMBO_NODE_ELEMENT)) {
            const GumboVector* children = &current->v.element.children;
            // Add children in reverse order so we process them in the correct order
            for (int i = static_cast<int>(children->length) - 1; i >= 0; --i) {
                stack.push_back(static_cast<GumboNode*>(children->data[i]));
            }
        }
    }
}

} // namespace cutysoup
