#pragma once

#include <vector>
#include <string>
#include <memory>
#include <unordered_map>
#include <variant>
#include <functional>
#include "gumbo.h"
#include "node.h"

namespace cutysoup {

// Forward declarations
class Tree;
class Node;

/**
 * Zero-Context-Switch Batch Operations
 * 
 * REVOLUTIONARY APPROACH:
 * - All operations happen in single C++ call
 * - No Python-C++ context switches during processing
 * - Results returned as primitive types (strings, ints)
 * - Node objects created only when explicitly requested
 * - Massive performance gains for batch operations
 */

// Batch operation types
enum class BatchOp {
    FIND_ALL_TAG,
    FIND_ALL_CLASS,
    FIND_BY_ID,
    COUNT_TAG,
    COUNT_CLASS,
    EXTRACT_TEXT,
    EXTRACT_ATTRIBUTES,
    GET_TAG_NAMES
};

// Batch query structure
struct BatchQuery {
    BatchOp operation;
    std::string target;           // tag name, class name, or id
    std::string attribute_name;   // for attribute extraction
    bool include_children = true; // for text extraction
    
    BatchQuery(BatchOp op, const std::string& tgt, const std::string& attr = "", bool children = true)
        : operation(op), target(tgt), attribute_name(attr), include_children(children) {}
};

// Batch result types (no Node objects - just primitive data)
struct ElementInfo {
    std::string tag_name;
    std::string text_content;
    std::string id;
    std::vector<std::string> classes;
    std::unordered_map<std::string, std::string> attributes;
    size_t element_index;  // For later Node creation if needed
};

using BatchResult = std::variant<
    std::vector<ElementInfo>,    // For find operations
    std::vector<std::string>,    // For text/attribute extraction
    std::vector<size_t>,         // For counts
    size_t                       // For single count
>;

class ZeroContextBatch {
public:
    explicit ZeroContextBatch(const Tree* tree);
    
    // ULTRA-FAST: Execute multiple operations in single C++ call
    std::vector<BatchResult> execute_batch(const std::vector<BatchQuery>& queries);
    
    // ZERO-CONTEXT: Get primitive results without Node creation
    std::vector<std::string> get_all_text_by_tag(const std::string& tag_name);
    std::vector<std::string> get_all_text_by_class(const std::string& class_name);
    std::vector<std::string> get_all_attributes(const std::string& tag_name, const std::string& attr_name);
    
    // BULK COUNTING: Ultra-fast element counting
    std::unordered_map<std::string, size_t> count_all_tags();
    std::unordered_map<std::string, size_t> count_all_classes();
    
    // STREAMING: Generator-style results (no memory overhead)
    void stream_elements_by_tag(const std::string& tag_name, 
                               std::function<bool(const ElementInfo&)> callback);
    
    // LAZY NODE CREATION: Create Node objects only when requested
    std::vector<std::shared_ptr<Node>> create_nodes_from_indices(const std::vector<size_t>& indices);
    
    // CACHING: Cache frequently accessed results
    void enable_result_cache(bool enabled = true) { cache_enabled_ = enabled; }
    void clear_cache();
    
    // STATISTICS
    struct PerformanceStats {
        size_t total_operations = 0;
        size_t cache_hits = 0;
        size_t context_switches_avoided = 0;
        double total_time_saved_ms = 0.0;
    };
    
    PerformanceStats get_stats() const { return stats_; }

private:
    const Tree* tree_;
    bool cache_enabled_ = true;
    mutable PerformanceStats stats_;
    
    // Pre-indexed element storage for ultra-fast access
    std::vector<GumboNode*> all_elements_;
    std::unordered_map<std::string, std::vector<size_t>> tag_indices_;
    std::unordered_map<std::string, std::vector<size_t>> class_indices_;
    std::unordered_map<std::string, size_t> id_indices_;
    
    // Result caching
    mutable std::unordered_map<std::string, BatchResult> result_cache_;
    
    // Core processing methods
    void build_fast_indices();
    ElementInfo extract_element_info(GumboNode* node, size_t index) const;
    std::string extract_text_content(GumboNode* node, bool include_children) const;
    std::vector<std::string> extract_classes(const char* class_attr) const;
    
    // Cache management
    std::string generate_cache_key(const BatchQuery& query) const;
    bool try_get_cached_result(const std::string& key, BatchResult& result) const;
    void cache_result(const std::string& key, const BatchResult& result) const;
};

} // namespace cutysoup