#pragma once

#include <string>
#include <vector>
#include <map>
#include <memory>
#include "gumbo.h"

namespace cutysoup {

class Tree;
class SimpleParallelWalker;
class OptimizedParallelWalker;
class UltraFastWalker;
class LightningWalker;

class Node : public std::enable_shared_from_this<Node> {
public:
    Node(GumboNode* gumbo_node, const Tree* tree);
    ~Node() = default;
    
    // Basic properties
    std::string get_name() const;
    std::map<std::string, std::string> get_attributes() const;
    std::string get_attribute(const std::string& name) const;
    std::string get_text() const;
    std::string get_text_with_separator(const std::string& separator) const;
    std::string get_text_stripped() const;
    std::string get_text_with_separator_stripped(const std::string& separator) const;
    std::vector<std::string> get_strings() const;
    std::vector<std::string> get_stripped_strings() const;
    std::string get_direct_text() const;
    
    // Node type checking
    bool is_element() const;
    bool is_text() const;
    bool is_document() const;
    
    // Tree navigation
    std::shared_ptr<Node> get_parent() const;
    std::vector<std::shared_ptr<Node>> get_children() const;
    std::shared_ptr<Node> get_next_sibling() const;
    std::shared_ptr<Node> get_previous_sibling() const;
    
    // Advanced navigation
    std::shared_ptr<Node> get_next_element() const;
    std::shared_ptr<Node> get_previous_element() const;
    std::vector<std::shared_ptr<Node>> get_descendants() const;
    std::vector<std::shared_ptr<Node>> get_all_descendants_with_text() const;
    std::vector<std::shared_ptr<Node>> get_all_parents() const;
    std::vector<std::shared_ptr<Node>> get_all_next_siblings_including_text() const;
    std::vector<std::shared_ptr<Node>> get_all_previous_siblings_including_text() const;
    
    // Search functions
    std::vector<std::shared_ptr<Node>> find_all(const std::string& tag_name = "", 
                                               const std::map<std::string, std::string>& attrs = {}) const;
    std::shared_ptr<Node> find(const std::string& tag_name = "", 
                              const std::map<std::string, std::string>& attrs = {}) const;
    std::vector<std::shared_ptr<Node>> find_descendants_by_tag(const std::string& tag_name) const;
    
    // Bulk search functions (eliminate Python/C++ boundary overhead)
    std::vector<std::shared_ptr<Node>> find_all_bulk(const std::string& tag_name = "", 
                                                    const std::map<std::string, std::string>& attrs = {}) const;
    std::shared_ptr<Node> find_bulk(const std::string& tag_name = "", 
                                   const std::map<std::string, std::string>& attrs = {}) const;
    
    // High-performance parallel search functions
    std::vector<std::shared_ptr<Node>> find_all_parallel(const std::string& tag_name = "", 
                                                        const std::map<std::string, std::string>& attrs = {},
                                                        bool enable_parallel = true) const;
    std::shared_ptr<Node> find_parallel(const std::string& tag_name = "", 
                                       const std::map<std::string, std::string>& attrs = {},
                                       bool enable_parallel = true) const;
    
    // Optimized parallel search functions with reduced overhead
    std::vector<std::shared_ptr<Node>> find_all_parallel_optimized(const std::string& tag_name = "", 
                                                                  const std::map<std::string, std::string>& attrs = {},
                                                                  bool enable_parallel = true) const;
    std::shared_ptr<Node> find_parallel_optimized(const std::string& tag_name = "", 
                                                 const std::map<std::string, std::string>& attrs = {},
                                                 bool enable_parallel = true) const;
    
    // Ultra-fast sequential search functions with SIMD optimizations
    std::vector<std::shared_ptr<Node>> find_all_ultra_fast(const std::string& tag_name = "", 
                                                          const std::map<std::string, std::string>& attrs = {}) const;
    std::shared_ptr<Node> find_ultra_fast(const std::string& tag_name = "", 
                                         const std::map<std::string, std::string>& attrs = {}) const;
    
    // ZERO-CONTEXT METHODS: Return primitive data without Node creation overhead
    std::vector<std::string> get_all_text_by_tag(const std::string& tag_name) const;
    std::vector<std::string> get_all_text_by_class(const std::string& class_name) const; 
    std::vector<std::string> get_all_hrefs() const;
    std::vector<std::string> get_all_src_attributes() const;
    size_t count_elements_by_tag(const std::string& tag_name) const;
    size_t count_elements_by_class(const std::string& class_name) const;
    
    // DOM manipulation methods
    void decompose();
    std::shared_ptr<Node> extract();
    void clear();
    void replace_with(std::shared_ptr<Node> new_node);
    void append(std::shared_ptr<Node> child);
    void insert(int index, std::shared_ptr<Node> child);
    std::shared_ptr<Node> wrap(std::shared_ptr<Node> wrapper);
    std::shared_ptr<Node> unwrap();
    
    // Attribute manipulation
    bool has_attribute(const std::string& name) const;
    void set_attribute(const std::string& name, const std::string& value);
    void remove_attribute(const std::string& name);
    
    // Access to underlying Gumbo node
    GumboNode* get_gumbo_node() const { return gumbo_node_; }
    
    // Test method to verify compilation
    std::string test_method() const { return "test_works"; }

private:
    GumboNode* gumbo_node_;
    const Tree* tree_;
    
    // Helper functions
    void collect_text_recursive(GumboNode* node, std::string& result) const;
    void collect_text_parts_recursive(GumboNode* node, std::vector<std::string>& parts) const;
    void collect_strings_recursive(GumboNode* node, std::vector<std::string>& strings) const;
    void collect_descendants_recursive(GumboNode* node, std::vector<std::shared_ptr<Node>>& descendants) const;
    void collect_descendants_with_text_recursive(GumboNode* node, std::vector<std::shared_ptr<Node>>& descendants) const;
    void collect_matching_descendants_recursive(GumboNode* node, const std::string& tag_name,
                                               std::vector<std::shared_ptr<Node>>& results) const;
    void search_recursive(GumboNode* node, const std::string& tag_name, 
                         const std::map<std::string, std::string>& attrs,
                         std::vector<std::shared_ptr<Node>>& results) const;
    bool matches_criteria(GumboNode* node, const std::string& tag_name,
                         const std::map<std::string, std::string>& attrs) const;
    std::shared_ptr<Node> create_node(GumboNode* gumbo_node) const;
    static const GumboVector* get_child_vector(GumboNode* node);
    static std::string trim_whitespace(const std::string& value);
};

} // namespace cutysoup
