#include "../src/firefly.h" // Adjusted path to header in src directory
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

// Helper function to split string (basic)
std::vector<std::string> split(const std::string& s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

int main() {
    // Create client
    // Assumes the compiled library is accessible (e.g., in PATH or same dir)
    void* client = CreateClient("localhost", 6379);
    if (!client) {
        std::cerr << "Failed to create client" << std::endl;
        return 1;
    }
    std::cout << "Client created." << std::endl;

    // Authenticate if needed (replace with your password or remove if none)
    // if (!Authenticate(client, "your_password")) {
    //     std::cerr << "Authentication failed" << std::endl;
    //     DestroyClient(client);
    //     return 1;
    // }
    // std::cout << "Authentication successful." << std::endl;

    // String operations
    std::cout << "\n--- String Ops ---" << std::endl;
    if (StringSet(client, "cpp:test", "hello from c++")) {
        std::cout << "StringSet OK" << std::endl;
    }

    char* value = StringGet(client, "cpp:test");
    if (value) {
        std::cout << "StringGet: " << value << std::endl;
        FreeString(value); // IMPORTANT: Free the returned string
    }

    // List operations
    std::cout << "\n--- List Ops ---" << std::endl;
    ListLeftPush(client, "cpp:mylist", "item1");
    ListLeftPush(client, "cpp:mylist", "item2");
    ListRightPush(client, "cpp:mylist", "item3");
    std::cout << "LPUSH/RPUSH OK" << std::endl;
    
    char* popped = ListLeftPop(client, "cpp:mylist");
    if (popped) {
        std::cout << "ListLeftPop: " << popped << std::endl;
        FreeString(popped); // IMPORTANT: Free
    }

    // Get a range of elements (Updated for char* return)
    std::cout << "ListRange:" << std::endl;
    char* rangeStr = ListRange(client, "cpp:mylist", 0, -1);
    if (rangeStr) {
        std::string rangeResult(rangeStr);
        FreeString(rangeStr); // IMPORTANT: Free
        
        // Parse the newline-delimited string
        std::vector<std::string> range = split(rangeResult, '\n');
        for (size_t i = 0; i < range.size(); ++i) {
            std::cout << "  Element " << i << ": " << range[i] << std::endl;
        }
    } else {
        std::cout << "  (empty or error)" << std::endl;
    }
    
    // ListPosition
    int pos = ListPosition(client, "cpp:mylist", "item1", 0, 0);
    std::cout << "ListPosition of 'item1': " << pos << std::endl;

    // ListSet
    if (ListSet(client, "cpp:mylist", 0, "item1_updated")) {
         std::cout << "ListSet OK" << std::endl;
    }
    
    // ListRemove
    int removed = ListRemove(client, "cpp:mylist", 1, "item3");
    std::cout << "ListRemove ('item3', count 1): Removed " << removed << " elements" << std::endl;

    // ListTrim
    if (ListTrim(client, "cpp:mylist", 0, 0)) { // Trim to keep only the first element
        std::cout << "ListTrim OK" << std::endl;
    }
    
    // Verify trim
    char* finalRangeStr = ListRange(client, "cpp:mylist", 0, -1);
     if (finalRangeStr) {
        std::cout << "List after Trim: " << finalRangeStr << std::endl;
        FreeString(finalRangeStr);
    }

    // Hash operations
    std::cout << "\n--- Hash Ops ---" << std::endl;
    HashSet(client, "cpp:user:1", "name", "John C.");
    HashSet(client, "cpp:user:1", "email", "john.c@example.com");
    std::cout << "HashSet OK" << std::endl;
    
    char* name = HashGet(client, "cpp:user:1", "name");
    if (name) {
        std::cout << "HashGet 'name': " << name << std::endl;
        FreeString(name); // IMPORTANT: Free
    }
    
    // HashMultiSet
    if(HashMultiSet(client, "cpp:user:1", "city NewYork country USA")) {
         std::cout << "HashMultiSet OK" << std::endl;
    }

    // Get all hash fields (Updated for char* return)
    std::cout << "HashGetAll:" << std::endl;
    char* hashDataStr = HashGetAll(client, "cpp:user:1");
    if (hashDataStr) {
        std::string hashResult(hashDataStr);
        FreeString(hashDataStr); // IMPORTANT: Free
        
        // Parse the newline-delimited "field=value" string
        std::vector<std::string> pairs = split(hashResult, '\n');
        for (const auto& pair : pairs) {
            size_t eqPos = pair.find('=');
            if (eqPos != std::string::npos) {
                std::cout << "  " << pair.substr(0, eqPos) << ": " << pair.substr(eqPos + 1) << std::endl;
            }
        }
    } else {
        std::cout << "  (empty or error)" << std::endl;
    }

    // Execute a raw command
    std::cout << "\n--- Raw Command ---" << std::endl;
    char* result = ExecuteCommand(client, "PING", "");
    if (result) {
        std::cout << "PING result: " << result; // Result likely includes \r\n
        FreeString(result); // IMPORTANT: Free
    }

    // Pipeline operations (example)
    std::cout << "\n--- Pipeline Ops ---" << std::endl;
    if (SetPipelineMode(client, true)) {
        std::cout << "Pipeline mode enabled." << std::endl;
        SetBatchSize(client, 5);
        StringSet(client, "pipe:1", "a");
        StringSet(client, "pipe:2", "b");
        std::cout << " Queued: " << GetQueuedCommandCount(client) << std::endl;
        char* flushResult = FlushPipeline(client);
        if(flushResult) {
             std::cout << " Flushed Result: " << flushResult << std::endl;
             FreeString(flushResult);
        }
        SetPipelineMode(client, false);
        std::cout << "Pipeline mode disabled." << std::endl;
    }
    
    // Clean up string/list/hash keys used
    Delete(client, "cpp:test");
    Delete(client, "cpp:mylist");
    Delete(client, "cpp:user:1");
    Delete(client, "pipe:1");
    Delete(client, "pipe:2");

    // Destroy client
    std::cout << "\nDestroying client..." << std::endl;
    DestroyClient(client);
    std::cout << "Client destroyed." << std::endl;
    
    return 0;
} 