#pragma once

// JSON implementation types and helpers
// Internal header - do not include directly, use fl/stl/json.h instead

#include "fl/stl/int.h"
#include "fl/stl/string.h"
#include "fl/stl/vector.h"
#include "fl/stl/flat_map.h"
#include "fl/stl/variant.h"
#include "fl/stl/optional.h"
#include "fl/stl/shared_ptr.h"
#include "fl/stl/cctype.h"
#include "fl/stl/charconv.h"
#include "fl/stl/limits.h"
#include "fl/stl/cstddef.h"
#include "fl/stl/move.h"
#include "fl/stl/strstream.h"
#include "fl/stl/span.h"
#include "fl/stl/type_traits.h"
#include "fl/log/log.h"
#include "fl/task/promise.h" // For fl::task::Error type
#include "fl/stl/string_view.h"

#include "fl/stl/noexcept.h"

namespace fl {

struct json_value;

// Define Array and Object as pointers to avoid incomplete type issues
// We'll use heap-allocated containers for these to avoid alignment issues
using json_array = fl::vector<fl::shared_ptr<json_value>>;
using json_object = fl::flat_map<fl::string, fl::shared_ptr<json_value>, fl::StringFastLess>;

// parse_result struct to replace variant<T, task::Error>
template<typename T>
struct parse_result {
    T value;
    task::Error error;
    
    parse_result(const T& val) FL_NOEXCEPT : value(val), error() {}
    parse_result(const task::Error& err) FL_NOEXCEPT : value(), error(err) {}
    
    bool has_error() const FL_NOEXCEPT { return !error.is_empty(); }
    const T& get_value() const FL_NOEXCEPT { return value; }
    const task::Error& get_error() const FL_NOEXCEPT { return error; }
    
    // Implicit conversion operator to allow using parse_result as T directly
    operator const T&() const FL_NOEXCEPT {
        if (has_error()) {
            // This should ideally trigger some kind of error handling
            // For now, we'll just return the value (which might be default-initialized)
        }
        return value; 
    }
};

// Function to get a reference to a static null json_value
json_value& get_null_json_value() FL_NOEXCEPT;

// Function to get a reference to a static empty json_object
json_object& get_empty_json_obj() FL_NOEXCEPT;

// AI - pay attention to this - implementing visitor pattern
template<typename T>
struct default_value_visitor {
    const T& fallback;
    const T* result = nullptr;
    T storage; // Use instance storage instead of static

    default_value_visitor(const T& fb) FL_NOEXCEPT : fallback(fb) {}

    // This is the method that fl::variant expects
    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }

    // Specific overload for the type T
    void operator()(const T& value) FL_NOEXCEPT {
        result = &value;
    }
    
    // Special handling for integer conversions
    template<typename U>
    typename fl::enable_if<fl::is_integral<T>::value && fl::is_integral<U>::value, void>::type
    operator()(const U& value) FL_NOEXCEPT {
        // Convert between integer types
        storage = static_cast<T>(value);
        result = &storage;
    }
    
    // Special handling for floating point to integer conversion
    template<typename U>
    typename fl::enable_if<fl::is_integral<T>::value && fl::is_floating_point<U>::value, void>::type
    operator()(const U& value) FL_NOEXCEPT {
        // Convert float to integer
        storage = static_cast<T>(value);
        result = &storage;
    }
    
    // Special handling for integer to floating point conversion
    template<typename U>
    typename fl::enable_if<fl::is_floating_point<T>::value && fl::is_integral<U>::value, void>::type
    operator()(const U& value) FL_NOEXCEPT {
        // Convert integer to float
        storage = static_cast<T>(value);
        result = &storage;
    }
    
    // Special handling for floating point to floating point conversion
    template<typename U>
    typename fl::enable_if<fl::is_floating_point<T>::value && fl::is_floating_point<U>::value && !fl::is_same<T, U>::value, void>::type
    operator()(const U& value) FL_NOEXCEPT {
        // Convert between floating point types (e.g., double to float)
        storage = static_cast<T>(value);
        result = &storage;
    }
    
    // Generic overload for all other types
    template<typename U>
    typename fl::enable_if<
        !(fl::is_integral<T>::value && fl::is_integral<U>::value) FL_NOEXCEPT &&
        !(fl::is_integral<T>::value && fl::is_floating_point<U>::value) &&
        !(fl::is_floating_point<T>::value && fl::is_integral<U>::value) &&
        !(fl::is_floating_point<T>::value && fl::is_floating_point<U>::value && !fl::is_same<T, U>::value),
        void>::type
    operator()(const U&) {
        // Do nothing for other types
    }
    
    // Special handling for nullptr_t
    void operator()(const fl::nullptr_t&) {
        // Do nothing - will return fallback
    }
};

// Visitor for converting values to int
template<typename IntType = i64>
struct int_conversion_visitor {
    fl::optional<IntType> result;
    
    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }
    
    // Special handling to avoid conflict when IntType is i64
    template<typename T = IntType>
    typename fl::enable_if<!fl::is_same<T, i64>::value && !fl::is_same<T, double>::value, void>::type
    operator()(const IntType& value) FL_NOEXCEPT {
        result = value;
    }
    
    // Special handling for i64 case
    template<typename T = IntType>
    typename fl::enable_if<fl::is_same<T, i64>::value, void>::type
    operator()(const i64& value) FL_NOEXCEPT {
        result = value;
    }
    
    // Special handling for double case (when IntType is double)
    template<typename T = IntType>
    typename fl::enable_if<fl::is_same<T, double>::value, void>::type
    operator()(const double& value) FL_NOEXCEPT {
        result = value;
    }
    
    // Special handling to avoid conflict when IntType is i64
    // With overflow detection and logging
    template<typename T = IntType>
    typename fl::enable_if<!fl::is_same<T, i64>::value, void>::type
    operator()(const i64& value) FL_NOEXCEPT {
        // Check for overflow before casting
        // For signed types: check if value is within [min, max] range
        // For unsigned types: check if value is non-negative and within [0, max] range
        // Use parentheses around min/max to protect against Arduino min/max macros
        const i64 min_val = static_cast<i64>((fl::numeric_limits<IntType>::min)());
        const i64 max_val = static_cast<i64>((fl::numeric_limits<IntType>::max)());

        if (value < min_val || value > max_val) {
            // Log overflow error but still perform conversion (value will be truncated)
            FL_ERROR("JSON integer overflow: value " << value << " does not fit in target type (range: "
                     << min_val << " to " << max_val << "), truncating");
        }

        // Always perform conversion, even if overflow detected
        result = static_cast<IntType>(value);
    }
    
    void operator()(const bool& value) FL_NOEXCEPT {
        result = static_cast<IntType>(value ? 1 : 0);
    }

    // Special handling for float to int conversion
    void operator()(const float& value) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
        result = static_cast<IntType>(value);
    }

    // Special handling for double to int conversion
    template<typename T = IntType>
    typename fl::enable_if<!fl::is_same<T, double>::value, void>::type
    operator()(const double& value) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO INT
        result = static_cast<IntType>(value);
    }

    void operator()(const fl::string& str) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
        // Try to parse the string as an integer using FastLED's StringFormatter
        // Validate by checking if string contains only digits (and optional +/- sign)
        bool isValidInt = true;
        fl::size startPos = 0;
        
        // Check for sign
        if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
            startPos = 1;
        }
        
        // Check that all remaining characters are digits
        for (fl::size i = startPos; i < str.length(); i++) {
            if (!fl::isdigit(str[i])) {
                isValidInt = false;
                break;
            }
        }
        
        // If it looks like a valid integer, try to parse it
        if (isValidInt && str.length() > 0) {
            int parsed = fl::parseInt(str.c_str(), str.length());
            result = static_cast<IntType>(parsed);
        }
    }
    
    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types
    }
};

// Specialization for i64 to avoid template conflicts
template<>
struct int_conversion_visitor<i64> {
    fl::optional<i64> result;
    
    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }
    
    void operator()(const i64& value) FL_NOEXCEPT {
        result = value;
    }
    
    void operator()(const bool& value) FL_NOEXCEPT {
        result = value ? 1 : 0;
    }

    void operator()(const float& value) FL_NOEXCEPT {
        // AUTO CONVERT FLOAT TO INT. Route through int32 first to avoid the
        // direct (i64)float cast — libgcc's `__aeabi_f2lz` helper internally
        // chains through `_fixunssfdi.o` which anchors `__aeabi_dmul/dsub`
        // (soft-double helpers, ~6 KB on no-FPU targets). See FastLED #3002.
        // The variant only ever holds float (not double — see line 652), so
        // JSON numbers fitting in int32 cover every value the parser
        // currently emits; larger magnitudes saturate.
        if (value > static_cast<float>(2147483647)) {
            result = static_cast<i64>(2147483647);
        } else if (value < static_cast<float>(-2147483648.0f)) {
            result = static_cast<i64>(-2147483648LL);
        } else {
            result = static_cast<i64>(static_cast<fl::i32>(value));
        }
    }

    void operator()(const double& value) FL_NOEXCEPT {
        // Same #3002 reasoning — but the variant never holds `double`, so
        // this overload is dead code in practice. Keep the direct cast for
        // semantic completeness; LTO will remove it.
        result = static_cast<i64>(value);
    }

    void operator()(const fl::string& str) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT STRING TO INT
        // Try to parse the string as an integer using FastLED's StringFormatter
        // Validate by checking if string contains only digits (and optional +/- sign)
        bool isValidInt = true;
        fl::size startPos = 0;
        
        // Check for sign
        if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
            startPos = 1;
        }
        
        // Check that all remaining characters are digits
        for (fl::size i = startPos; i < str.length(); i++) {
            if (!fl::isdigit(str[i])) {
                isValidInt = false;
                break;
            }
        }
        
        // If it looks like a valid integer, try to parse it
        if (isValidInt && str.length() > 0) {
            int parsed = fl::parseInt(str.c_str(), str.length());
            result = static_cast<i64>(parsed);
        }
    }
    
    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types
    }
};

// Visitor for converting values to bool
struct BoolConversionVisitor {
    fl::optional<bool> result;

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }

    void operator()(const bool& value) FL_NOEXCEPT {
        result = value;
    }

    void operator()(const i64& value) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT INT TO BOOL
        // 0 → false, non-zero → true
        result = (value != 0);
    }

    void operator()(const float& value) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT FLOAT TO BOOL
        // 0.0 → false, non-zero → true
        result = (value != 0.0f);
    }

    void operator()(const double& value) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT DOUBLE TO BOOL
        // 0.0 → false, non-zero → true
        result = (value != 0.0);
    }

    void operator()(const fl::string& str) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT STRING TO BOOL
        // "true", "1", "yes", "on" (case insensitive) → true
        // "false", "0", "no", "off" (case insensitive) → false
        // Empty string → false
        // Invalid string → nullopt

        if (str.empty()) {
            result = false;
            return;
        }

        // Convert to lowercase for case-insensitive comparison
        fl::string lower = str;
        for (fl::size i = 0; i < lower.length(); i++) {
            lower[i] = fl::tolower(lower[i]);
        }

        // Check for true values
        if (lower == "true" || lower == "1" || lower == "yes" || lower == "on") {
            result = true;
            return;
        }

        // Check for false values
        if (lower == "false" || lower == "0" || lower == "no" || lower == "off") {
            result = false;
            return;
        }

        // Invalid string - don't set result (leave as nullopt)
    }

    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types (arrays, objects, null)
    }
};

// Visitor for converting values to float
template<typename FloatType = double>
struct float_conversion_visitor {
    fl::optional<FloatType> result;
    
    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }
    
    void operator()(const FloatType& value) FL_NOEXCEPT {
        result = value;
    }
    
    // Special handling to avoid conflict when FloatType is double
    template<typename T = FloatType>
    typename fl::enable_if<!fl::is_same<T, double>::value, void>::type
    operator()(const double& value) FL_NOEXCEPT {
        result = static_cast<FloatType>(value);
    }
    
    // Special handling to avoid conflict when FloatType is float
    template<typename T = FloatType>
    typename fl::enable_if<!fl::is_same<T, float>::value, void>::type
    operator()(const float& value) FL_NOEXCEPT {
        result = static_cast<FloatType>(value);
    }
    
    void operator()(const i64& value) FL_NOEXCEPT {
        // AUTO CONVERT INT TO FLOAT. Route through int32 first to avoid the
        // direct (FloatType)i64 cast — libgcc-nofp's `__aeabi_l2f` helper lives
        // in `_floatdisf.o` which anchors `__aeabi_dadd / dmul / i2d / ui2d / d2f`
        // (soft-double helpers, ~5 KB on no-FPU targets). Values fitting in
        // int32 cover every value the integer-only LowMemory JSON-RPC contract
        // emits; larger magnitudes saturate at INT32_MIN/MAX. See FastLED #3076.
        if (value > 2147483647LL) {
            result = static_cast<FloatType>(2147483647);
        } else if (value < -2147483648LL) {
            result = static_cast<FloatType>(-2147483648);
        } else {
            result = static_cast<FloatType>(static_cast<fl::i32>(value));
        }
    }

    void operator()(const bool& value) FL_NOEXCEPT {
        // Use float literals (1.0f / 0.0f), not double (1.0 / 0.0), to avoid
        // pulling the soft-double helpers. See FastLED #3076.
        result = static_cast<FloatType>(value ? 1.0f : 0.0f);
    }

    void operator()(const fl::string& str) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
        // Try to parse the string as a float using FastLED's StringFormatter
        // Validate by checking if string contains valid float characters
        bool isValidFloat = true;
        bool hasDecimal = false;
        fl::size startPos = 0;

        // Check for sign
        if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
            startPos = 1;
        }

        // Check that all remaining characters are valid for a float
        for (fl::size i = startPos; i < str.length(); i++) {
            char c = str[i];
            if (c == '.') {
                if (hasDecimal) {
                    // Multiple decimal points
                    isValidFloat = false;
                    break;
                }
                hasDecimal = true;
            } else if (!fl::isdigit(c) && c != 'e' && c != 'E') {
                isValidFloat = false;
                break;
            }
        }

        // If it looks like a valid float, try to parse it
        if (isValidFloat && str.length() > 0) {
            // For simple cases, we can use a more precise approach
            // Check if it's a simple decimal number
            bool isSimpleDecimal = true;
            for (fl::size i = startPos; i < str.length(); i++) {
                char c = str[i];
                if (c != '.' && !fl::isdigit(c)) {
                    isSimpleDecimal = false;
                    break;
                }
            }

            if (isSimpleDecimal) {
                // For simple decimals, we can do a more direct conversion
                float parsed = fl::parseFloat(str.c_str(), str.length());
                result = static_cast<FloatType>(parsed);
            } else {
                // For complex floats (with exponents), use the standard approach
                float parsed = fl::parseFloat(str.c_str(), str.length());
                result = static_cast<FloatType>(parsed);
            }
        }
    }
    
    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types
    }
};

// Specialization for double to avoid template conflicts
template<>
struct float_conversion_visitor<double> {
    fl::optional<double> result;
    
    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }
    
    void operator()(const double& value) FL_NOEXCEPT {
        result = value;
    }
    
    void operator()(const float& value) FL_NOEXCEPT {
        result = static_cast<double>(value);
    }
    
    void operator()(const i64& value) FL_NOEXCEPT {
        // AUTO CONVERT INT TO FLOAT. Route through int32 to avoid pulling
        // libgcc-nofp's `_floatdisf.o` soft-double cascade on no-FPU targets.
        // The double path (`as_double()`) is DCE'd from LowMemory builds today,
        // but keep the int32-route here as defense-in-depth. See FastLED #3076.
        if (value > 2147483647LL) {
            result = static_cast<double>(2147483647);
        } else if (value < -2147483648LL) {
            result = static_cast<double>(-2147483648);
        } else {
            result = static_cast<double>(static_cast<fl::i32>(value));
        }
    }
    
    void operator()(const bool& value) FL_NOEXCEPT {
        result = value ? 1.0 : 0.0;
    }
    
    void operator()(const fl::string& str) FL_NOEXCEPT {
        // NEW INSTRUCTIONS: AUTO CONVERT STRING TO FLOAT
        // Try to parse the string as a float using FastLED's StringFormatter
        // Validate by checking if string contains valid float characters
        bool isValidFloat = true;
        bool hasDecimal = false;
        fl::size startPos = 0;
        
        // Check for sign
        if (str.length() > 0 && (str[0] == '+' || str[0] == '-')) {
            startPos = 1;
        }
        
        // Check that all remaining characters are valid for a float
        for (fl::size i = startPos; i < str.length(); i++) {
            char c = str[i];
            if (c == '.') {
                if (hasDecimal) {
                    // Multiple decimal points
                    isValidFloat = false;
                    break;
                }
                hasDecimal = true;
            } else if (!fl::isdigit(c) && c != 'e' && c != 'E') {
                isValidFloat = false;
                break;
            }
        }
        
        // If it looks like a valid float, try to parse it
        if (isValidFloat && str.length() > 0) {
            // For simple cases, we can use a more precise approach
            // Check if it's a simple decimal number
            bool isSimpleDecimal = true;
            for (fl::size i = startPos; i < str.length(); i++) {
                char c = str[i];
                if (c != '.' && !fl::isdigit(c)) {
                    isSimpleDecimal = false;
                    break;
                }
            }
            
            if (isSimpleDecimal) {
                // For simple decimals, we can do a more direct conversion
                float parsed = fl::parseFloat(str.c_str(), str.length());
                result = static_cast<double>(parsed);
            } else {
                // For complex floats (with exponents), use the standard approach
                float parsed = fl::parseFloat(str.c_str(), str.length());
                result = static_cast<double>(parsed);
            }
        }
    }
    
    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types
    }
};

// Visitor for converting values to string
struct StringConversionVisitor {
    fl::optional<fl::string> result;

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }

    void operator()(const fl::string& value) FL_NOEXCEPT {
        result = value;
    }

    void operator()(const i64& value) FL_NOEXCEPT {
        // Convert integer to string
        result = fl::to_string(value);
    }

    void operator()(const double& value) FL_NOEXCEPT {
        // Convert double to string with higher precision for JSON representation
        result = fl::to_string(static_cast<float>(value), 6);
    }

    void operator()(const float& value) FL_NOEXCEPT {
        // Convert float to string with higher precision for JSON representation
        result = fl::to_string(value, 6);
    }

    void operator()(const bool& value) FL_NOEXCEPT {
        // Convert bool to string
        result = value ? "true" : "false";
    }

    void operator()(const fl::nullptr_t&) FL_NOEXCEPT {
        // Convert null to string
        result = "null";
    }

    template<typename T>
    void operator()(const T&) FL_NOEXCEPT {
        // Do nothing for other types (arrays, objects)
    }
};

// Visitor for getting size of arrays and objects
struct SizeVisitor {
    size_t result = 0;

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT {
        // Dispatch to the correct operator() overload
        (*this)(value);
    }

    void operator()(const json_array& arr) FL_NOEXCEPT { result = arr.size(); }
    void operator()(const json_object& obj) FL_NOEXCEPT { result = obj.size(); }
    void operator()(const fl::vector<i16>& vec) FL_NOEXCEPT { result = vec.size(); }
    void operator()(const fl::vector<u8>& vec) FL_NOEXCEPT { result = vec.size(); }
    void operator()(const fl::vector<float>& vec) FL_NOEXCEPT { result = vec.size(); }

    // Generic fallback for other types (primitives, null)
    void operator()(const fl::nullptr_t&) FL_NOEXCEPT { result = 0; }
    void operator()(const bool&) FL_NOEXCEPT { result = 0; }
    void operator()(const i64&) FL_NOEXCEPT { result = 0; }
    void operator()(const float&) FL_NOEXCEPT { result = 0; }
    void operator()(const fl::string&) FL_NOEXCEPT { result = 0; }
};

// Forward declarations for visitors (defined after json_value)
template<typename T> struct NumericExtractVisitor;
template<typename T> struct CopyToVisitor;
template<typename T, typename OutputIt> struct CopyToOutputIteratorVisitor;

// The JSON node
struct json_value {
    // Forward declarations for nested iterator classes
    class iterator;
    class const_iterator;
    
    // Friend declarations
    friend class json;
    
    // The variant holds exactly one of these alternatives
    using variant_t = fl::variant<
        fl::nullptr_t,   // null
        bool,            // true/false
        i64,         // integer
        float,           // floating-point (changed from double to float)
        fl::string,      // string
        json_array,           // array
        json_object,          // object
        fl::vector<i16>, // audio data (specialized array of int16_t)
        fl::vector<u8>, // byte data (specialized array of uint8_t)
        fl::vector<float>    // float data (specialized array of float)
    >;

    typedef json_value::iterator iterator;
    typedef json_value::const_iterator const_iterator;

    variant_t data;

    // Constructors
    json_value() FL_NOEXCEPT : data(nullptr) {}
    json_value(fl::nullptr_t) FL_NOEXCEPT : data(nullptr) {}
    json_value(bool b) FL_NOEXCEPT : data(b) {}
    json_value(i64 i) FL_NOEXCEPT : data(i) {}
    // Explicit int/unsigned constructors to prevent ambiguity on platforms where
    // int != i64 (e.g., 32-bit ARM with GCC). Without these, int is equally
    // convertible to bool, i64, and float.
    json_value(int i) FL_NOEXCEPT : data(static_cast<i64>(i)) {}
    json_value(unsigned int i) FL_NOEXCEPT : data(static_cast<i64>(i)) {}
    json_value(float f) FL_NOEXCEPT : data(f) {}  // Changed from double to float
    json_value(const fl::string& s) FL_NOEXCEPT : data(s) {
    }
    json_value(const json_array& a) FL_NOEXCEPT : data(a) {
        //FL_WARN("Created json_value with array");
    }
    json_value(const json_object& o) FL_NOEXCEPT : data(o) {
        //FL_WARN("Created json_value with object");
    }
    json_value(const fl::vector<i16>& audio) FL_NOEXCEPT : data(audio) {
        //FL_WARN("Created json_value with audio data");
    }
    
    json_value(fl::vector<i16>&& audio) FL_NOEXCEPT : data(fl::move(audio)) {
        //FL_WARN("Created json_value with moved audio data");
    }
    
    json_value(const fl::vector<u8>& bytes) FL_NOEXCEPT : data(bytes) {
        //FL_WARN("Created json_value with byte data");
    }
    
    json_value(fl::vector<u8>&& bytes) FL_NOEXCEPT : data(fl::move(bytes)) {
        //FL_WARN("Created json_value with moved byte data");
    }
    
    json_value(const fl::vector<float>& floats) FL_NOEXCEPT : data(floats) {
        //FL_WARN("Created json_value with float data");
    }
    
    json_value(fl::vector<float>&& floats) FL_NOEXCEPT : data(fl::move(floats)) {
        //FL_WARN("Created json_value with moved float data");
    }

    // Copy constructor
    json_value(const json_value& other) FL_NOEXCEPT : data(other.data) {}

    json_value& operator=(const json_value& other) FL_NOEXCEPT {
        data = other.data;
        return *this;
    }

    json_value& operator=(json_value&& other) FL_NOEXCEPT {
        data = fl::move(other.data);
        return *this;
    }

    template<typename T>
    typename fl::enable_if<!fl::is_same<typename fl::remove_cv<typename fl::remove_reference<T>::type>::type, json_value>::value, json_value&>::type
    operator=(T&& value) FL_NOEXCEPT {
        data = fl::forward<T>(value);
        return *this;
    }

    json_value& operator=(fl::nullptr_t) FL_NOEXCEPT {
        data = nullptr;
        return *this;
    }

    json_value& operator=(bool b) FL_NOEXCEPT {
        data = b;
        return *this;
    }

    json_value& operator=(i64 i) FL_NOEXCEPT {
        data = i;
        return *this;
    }

    json_value& operator=(double d) FL_NOEXCEPT {
        data = static_cast<float>(d);
        return *this;
    }
    
    json_value& operator=(float f) FL_NOEXCEPT {
        data = f;
        return *this;
    }

    json_value& operator=(fl::string s) FL_NOEXCEPT {
        data = fl::move(s);
        return *this;
    }

    json_value& operator=(json_array a) FL_NOEXCEPT {
        data = fl::move(a);
        return *this;
    }
    
    json_value& operator=(fl::vector<i16> audio) FL_NOEXCEPT {
        data = fl::move(audio);
        return *this;
    }
    
    json_value& operator=(fl::vector<u8> bytes) FL_NOEXCEPT {
        data = fl::move(bytes);
        return *this;
    }
    
    json_value& operator=(fl::vector<float> floats) FL_NOEXCEPT {
        data = fl::move(floats);
        return *this;
    }

    // Special constructor for char values
    static fl::shared_ptr<json_value> from_char(char c) FL_NOEXCEPT {
        return fl::make_shared<json_value>(fl::string(1, c));
    }
    
    // Visitor pattern implementation
    template<typename Visitor>
    auto visit(Visitor&& visitor) FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{})) {
        return data.visit(fl::forward<Visitor>(visitor));
    }
    
    template<typename Visitor>
    auto visit(Visitor&& visitor) const FL_NOEXCEPT -> decltype(visitor(fl::nullptr_t{})) {
        return data.visit(fl::forward<Visitor>(visitor));
    }

    // Type queries - using is<T>() instead of index() for fl::variant
    bool is_null() const FL_NOEXCEPT { 
        //FL_WARN("is_null called, tag=" << data.tag());
        return data.is<fl::nullptr_t>(); 
    }
    bool is_bool() const FL_NOEXCEPT { 
        //FL_WARN("is_bool called, tag=" << data.tag());
        return data.is<bool>(); 
    }
    bool is_int() const FL_NOEXCEPT {
        //FL_WARN("is_int called, tag=" << data.tag());
        return data.is<i64>();
    }
    bool is_double() const FL_NOEXCEPT { 
        //FL_WARN("is_double called, tag=" << data.tag());
        return data.is<float>(); 
    }
    bool is_float() const FL_NOEXCEPT {
        return data.is<float>();
    }
    // is_number() returns true if the value is any numeric type (int or float)
    bool is_number() const FL_NOEXCEPT {
        return is_int() || is_float();
    }
    bool is_string() const FL_NOEXCEPT { 
        //FL_WARN("is_string called, tag=" << data.tag());
        return data.is<fl::string>(); 
    }
    // Visitor for array type checking
    struct IsArrayVisitor {
        bool result = false;
        
        template<typename T>
        void accept(const T& value) FL_NOEXCEPT {
            // Dispatch to the correct operator() overload
            (*this)(value);
        }
        
        // json_array is an array
        void operator()(const json_array&) FL_NOEXCEPT {
            result = true;
        }
        
        // Specialized array types ARE arrays
        void operator()(const fl::vector<i16>&) FL_NOEXCEPT {
            result = true;  // Audio data is still an array
        }
        
        void operator()(const fl::vector<u8>&) FL_NOEXCEPT {
            result = true;  // Byte data is still an array
        }
        
        void operator()(const fl::vector<float>&) FL_NOEXCEPT {
            result = true;  // Float data is still an array
        }
        
        // Generic handler for all other types
        template<typename T>
        void operator()(const T&) FL_NOEXCEPT {
            result = false;
        }
    };
    
    bool is_array() const FL_NOEXCEPT { 
        //FL_WARN("is_array called, tag=" << data.tag());
        IsArrayVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    // Returns true only for json_array (not specialized array types)
    bool is_generic_array() const FL_NOEXCEPT {
        return data.is<json_array>();
    }
    
    bool is_object() const FL_NOEXCEPT { 
        //FL_WARN("is_object called, tag=" << data.tag());
        return data.is<json_object>(); 
    }
    bool is_audio() const FL_NOEXCEPT {
        //FL_WARN("is_audio called, tag=" << data.tag());
        return data.is<fl::vector<i16>>();
    }
    bool is_bytes() const FL_NOEXCEPT {
        //FL_WARN("is_bytes called, tag=" << data.tag());
        return data.is<fl::vector<u8>>();
    }
    bool is_floats() const FL_NOEXCEPT {
        //FL_WARN("is_floats called, tag=" << data.tag());
        return data.is<fl::vector<float>>();
    }

    // Safe extractors (return optional values, not references)
    fl::optional<bool> as_bool() FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }

        BoolConversionVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<i64> as_int() FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        int_conversion_visitor<i64> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    template<typename IntType>
    fl::optional<IntType> as_int() FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        int_conversion_visitor<IntType> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<double> as_double() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        float_conversion_visitor<double> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<float> as_float() FL_NOEXCEPT {
        return as_float<float>();
    }
    
    template<typename FloatType>
    fl::optional<FloatType> as_float() FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        float_conversion_visitor<FloatType> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<fl::string> as_string() FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        StringConversionVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    // Zero-copy pointer accessors (non-const)
    json_array*           as_array() FL_NOEXCEPT { return data.ptr<json_array>(); }
    json_object*          as_object() FL_NOEXCEPT { return data.ptr<json_object>(); }

    // Const overloads
    fl::optional<bool> as_bool() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }

        BoolConversionVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<i64> as_int() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        int_conversion_visitor<i64> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    template<typename IntType>
    fl::optional<IntType> as_int() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        int_conversion_visitor<IntType> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<float> as_float() const FL_NOEXCEPT {
        return as_float<float>();
    }
    
    template<typename FloatType>
    fl::optional<FloatType> as_float() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        float_conversion_visitor<FloatType> visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    fl::optional<fl::string> as_string() const FL_NOEXCEPT {
        // Check if we have a valid value first
        if (data.empty()) {
            return fl::nullopt;
        }
        
        StringConversionVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }
    
    // Zero-copy pointer accessors (const)
    const json_array*           as_array()   const FL_NOEXCEPT { return data.ptr<json_array>(); }
    const json_object*          as_object()  const FL_NOEXCEPT { return data.ptr<json_object>(); }

    // Explicit copy methods - use when you need an owned copy or packed-array conversion
    fl::optional<json_array> clone_array() const FL_NOEXCEPT {
        auto ptr = data.ptr<json_array>();
        if (ptr) return fl::optional<json_array>(*ptr);
        // Handle specialized array types by converting them to regular json_array
        if (data.is<fl::vector<i16>>()) {
            auto audioPtr = data.ptr<fl::vector<i16>>();
            json_array result;
            for (const auto& item : *audioPtr) {
                result.push_back(fl::make_shared<json_value>(static_cast<i64>(item)));
            }
            return fl::optional<json_array>(result);
        }
        if (data.is<fl::vector<u8>>()) {
            auto bytePtr = data.ptr<fl::vector<u8>>();
            json_array result;
            for (const auto& item : *bytePtr) {
                result.push_back(fl::make_shared<json_value>(static_cast<i64>(item)));
            }
            return fl::optional<json_array>(result);
        }
        if (data.is<fl::vector<float>>()) {
            auto floatPtr = data.ptr<fl::vector<float>>();
            json_array result;
            for (const auto& item : *floatPtr) {
                result.push_back(fl::make_shared<json_value>(item));
            }
            return fl::optional<json_array>(result);
        }
        return fl::nullopt;
    }
    fl::optional<json_object> clone_object() const FL_NOEXCEPT {
        auto ptr = data.ptr<json_object>();
        return ptr ? fl::optional<json_object>(*ptr) : fl::nullopt;
    }

    // Copy packed-array elements into a caller-owned span with type conversion.
    // Returns number of elements copied (min of array size and span size).
    // Returns 0 if this value is not a numeric array.
    template<typename T>
    size_t copy_to(fl::span<T> out) const FL_NOEXCEPT {
        CopyToVisitor<T> visitor(out);
        data.visit(visitor);
        return visitor.result;
    }

    // Stream packed-array elements into an output iterator with type conversion.
    // Use with fl::back_inserter(container) to append to any container.
    // Returns number of elements written. Returns 0 if not a numeric array.
    template<typename T, typename OutputIt>
    size_t copy_to_output_iterator(OutputIt out) const FL_NOEXCEPT {
        CopyToOutputIteratorVisitor<T, OutputIt> visitor(out);
        data.visit(visitor);
        return visitor.result;
    }

    // Overload for back_insert_iterator: T deduced from container's value_type
    template<typename Container>
    size_t copy_to_output_iterator(fl::back_insert_iterator<Container> out) const FL_NOEXCEPT {
        using T = typename Container::value_type;
        CopyToOutputIteratorVisitor<T, fl::back_insert_iterator<Container>> visitor(out);
        data.visit(visitor);
        return visitor.result;
    }

    // Generic getter template method
    template<typename T>
    fl::optional<T> get() const FL_NOEXCEPT {
        auto ptr = data.ptr<T>();
        return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
    }
    
    template<typename T>
    fl::optional<T> get() FL_NOEXCEPT {
        auto ptr = data.ptr<T>();
        return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
    }

    // Iterator support for objects and arrays
    iterator begin() FL_NOEXCEPT {
        if (is_object()) {
            auto ptr = data.ptr<json_object>();
            return iterator(ptr->begin());
        }
        // Use temporary empty object to avoid static initialization conflicts with Teensy
        return iterator(json_object().begin());
    }
    
    iterator end() FL_NOEXCEPT {
        if (is_object()) {
            auto ptr = data.ptr<json_object>();
            return iterator(ptr->end());
        }
        // Use temporary empty object to avoid static initialization conflicts with Teensy
        return iterator(json_object().end());
    }
    
    const_iterator begin() const FL_NOEXCEPT {
        if (is_object()) {
            auto ptr = data.ptr<const json_object>();
            if (!ptr) return const_iterator::from_iterator(json_object().begin());
            return const_iterator::from_iterator(ptr->begin());
        }
        // Use temporary empty object to avoid static initialization conflicts with Teensy
        return const_iterator::from_iterator(json_object().begin());
    }
    
    const_iterator end() const FL_NOEXCEPT {
        if (is_object()) {
            auto ptr = data.ptr<const json_object>();
            if (!ptr) return const_iterator::from_iterator(json_object().end());
            return const_iterator::from_iterator(ptr->end());
        }
        // Use temporary empty object to avoid static initialization conflicts with Teensy
        return const_iterator::from_iterator(json_object().end());
    }
    
    // Iterator support for packed arrays
    template<typename T>
    class array_iterator {
    private:
        using variant_t = typename json_value::variant_t;
        variant_t* mVariant;
        size_t mIndex;
        
        // Helper to get the size of the array regardless of its type
        size_t get_size() const FL_NOEXCEPT {
            if (!mVariant) return 0;
            
            if (mVariant->is<json_array>()) {
                auto ptr = mVariant->ptr<json_array>();
                return ptr ? ptr->size() : 0;
            }
            
            if (mVariant->is<fl::vector<i16>>()) {
                auto ptr = mVariant->ptr<fl::vector<i16>>();
                return ptr ? ptr->size() : 0;
            }
            
            if (mVariant->is<fl::vector<u8>>()) {
                auto ptr = mVariant->ptr<fl::vector<u8>>();
                return ptr ? ptr->size() : 0;
            }
            
            if (mVariant->is<fl::vector<float>>()) {
                auto ptr = mVariant->ptr<fl::vector<float>>();
                return ptr ? ptr->size() : 0;
            }
            
            return 0;
        }
        
        // Helper to convert current element to target type T
        parse_result<T> get_value() const FL_NOEXCEPT {
            if (!mVariant || mIndex >= get_size()) {
                return parse_result<T>(task::Error("Index out of bounds"));
            }
            
            if (mVariant->is<json_array>()) {
                auto ptr = mVariant->ptr<json_array>();
                if (ptr && mIndex < ptr->size() && (*ptr)[mIndex]) {
                    auto& val = *((*ptr)[mIndex]);
                    
                    // Try to convert to T using the json_value conversion methods
                    // Using FastLED type traits instead of std:: ones
                    if (fl::is_same<T, bool>::value) {
                        auto opt = val.as_bool();
                        if (opt) {
                            return parse_result<T>(*opt);
                        } else {
                            return parse_result<T>(task::Error("Cannot convert to bool"));
                        }
                    } else if (fl::is_integral<T>::value && fl::is_signed<T>::value) {
                        auto opt = val.template as_int<T>();
                        if (opt) {
                            return parse_result<T>(*opt);
                        } else {
                            return parse_result<T>(task::Error("Cannot convert to signed integer"));
                        }
                    } else if (fl::is_integral<T>::value && !fl::is_signed<T>::value) {
                        // For unsigned types, we check that it's integral but not signed
                        auto opt = val.template as_int<T>();
                        if (opt) {
                            return parse_result<T>(*opt);
                        } else {
                            return parse_result<T>(task::Error("Cannot convert to unsigned integer"));
                        }
                    } else if (fl::is_floating_point<T>::value) {
                        auto opt = val.template as_float<T>();
                        if (opt) {
                            return parse_result<T>(*opt);
                        } else {
                            return parse_result<T>(task::Error("Cannot convert to floating point"));
                        }
                    }
                } else {
                    return parse_result<T>(task::Error("Invalid array access"));
                }
            }
            
            if (mVariant->is<fl::vector<i16>>()) {
                auto ptr = mVariant->ptr<fl::vector<i16>>();
                if (ptr && mIndex < ptr->size()) {
                    return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
                } else {
                    return parse_result<T>(task::Error("Index out of bounds in i16 array"));
                }
            }
            
            if (mVariant->is<fl::vector<u8>>()) {
                auto ptr = mVariant->ptr<fl::vector<u8>>();
                if (ptr && mIndex < ptr->size()) {
                    return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
                } else {
                    return parse_result<T>(task::Error("Index out of bounds in u8 array"));
                }
            }
            
            if (mVariant->is<fl::vector<float>>()) {
                auto ptr = mVariant->ptr<fl::vector<float>>();
                if (ptr && mIndex < ptr->size()) {
                    return parse_result<T>(static_cast<T>((*ptr)[mIndex]));
                } else {
                    return parse_result<T>(task::Error("Index out of bounds in float array"));
                }
            }
            
            return parse_result<T>(task::Error("Unknown array type"));
        }
        
    public:
        array_iterator() FL_NOEXCEPT : mVariant(nullptr), mIndex(0) {}
        array_iterator(variant_t* variant, size_t index) FL_NOEXCEPT : mVariant(variant), mIndex(index) {}
        
        parse_result<T> operator*() const FL_NOEXCEPT {
            return get_value();
        }
        
        array_iterator& operator++() FL_NOEXCEPT {
            ++mIndex;
            return *this;
        }
        
        array_iterator operator++(int) FL_NOEXCEPT {
            array_iterator tmp(*this);
            ++(*this);
            return tmp;
        }
        
        bool operator!=(const array_iterator& other) const FL_NOEXCEPT {
            return mIndex != other.mIndex || mVariant != other.mVariant;
        }
        
        bool operator==(const array_iterator& other) const FL_NOEXCEPT {
            return mIndex == other.mIndex && mVariant == other.mVariant;
        }
    };
    
    // Begin/end methods for array iteration
    template<typename T>
    array_iterator<T> begin_array() FL_NOEXCEPT {
        if (is_array()) {
            return array_iterator<T>(&data, 0);
        }
        return array_iterator<T>();
    }
    
    template<typename T>
    array_iterator<T> end_array() FL_NOEXCEPT {
        if (is_array()) {
            return array_iterator<T>(&data, size());
        }
        return array_iterator<T>();
    }
    
    template<typename T>
    array_iterator<T> begin_array() const FL_NOEXCEPT {
        if (is_array()) {
            return array_iterator<T>(const_cast<variant_t*>(&data), 0);
        }
        return array_iterator<T>();
    }
    
    template<typename T>
    array_iterator<T> end_array() const FL_NOEXCEPT {
        if (is_array()) {
            return array_iterator<T>(const_cast<variant_t*>(&data), size());
        }
        return array_iterator<T>();
    }
    
    // Free functions for range-based for loops
    friend iterator begin(json_value& v) FL_NOEXCEPT { return v.begin(); }
    friend iterator end(json_value& v) FL_NOEXCEPT { return v.end(); }
    friend const_iterator begin(const json_value& v) FL_NOEXCEPT { return v.begin(); }
    friend const_iterator end(const json_value& v) FL_NOEXCEPT { return v.end(); }

    // Indexing for fluid chaining
    json_value& operator[](size_t idx) FL_NOEXCEPT {
        if (!is_array()) data = json_array{};
        // Handle regular json_array
        if (data.is<json_array>()) {
            auto ptr = data.ptr<json_array>();
            if (!ptr) return get_null_json_value(); // Handle error case
            auto &arr = *ptr;
            if (idx >= arr.size()) {
                // Resize array and fill with null values
                for (size_t i = arr.size(); i <= idx; i++) {
                    arr.push_back(fl::make_shared<json_value>());
                }
            }
            if (idx >= arr.size()) return get_null_json_value(); // Handle error case
            return *arr[idx];
        }
        // For packed arrays, we need to convert them to regular arrays first
        // This is needed for compatibility with existing code that expects json_array
        if (data.is<fl::vector<i16>>() ||
            data.is<fl::vector<u8>>() ||
            data.is<fl::vector<float>>()) {
            // Convert to regular json_array (needs a copy/conversion)
            auto arr = clone_array();
            if (arr) {
                data = fl::move(*arr);
                auto ptr = data.ptr<json_array>();
                if (!ptr) return get_null_json_value();
                auto &jsonArr = *ptr;
                if (idx >= jsonArr.size()) {
                    // Resize array and fill with null values
                    for (size_t i = jsonArr.size(); i <= idx; i++) {
                        jsonArr.push_back(fl::make_shared<json_value>());
                    }
                }
                if (idx >= jsonArr.size()) return get_null_json_value();
                return *jsonArr[idx];
            }
        }
        return get_null_json_value();
    }
    
    json_value& operator[](const fl::string &key) FL_NOEXCEPT {
        if (!is_object()) data = json_object{};
        auto ptr = data.ptr<json_object>();
        if (!ptr) return get_null_json_value(); // Handle error case
        auto &obj = *ptr;
        if (obj.find(key) == obj.end()) {
            // Create a new entry if key doesn't exist
            obj[key] = fl::make_shared<json_value>();
        }
        return *obj[key];
    }

    // Default-value operator (pipe)
    template<typename T>
    T operator|(const T& fallback) const FL_NOEXCEPT {
        default_value_visitor<T> visitor(fallback);
        data.visit(visitor);
        return visitor.result ? *visitor.result : fallback;
    }
    
    // Explicit method for default values (alternative to operator|)
    template<typename T>
    T as_or(const T& fallback) const FL_NOEXCEPT {
        default_value_visitor<T> visitor(fallback);
        data.visit(visitor);
        return visitor.result ? *visitor.result : fallback;
    }

    // Contains methods for checking existence
    bool contains(size_t idx) const FL_NOEXCEPT {
        // Handle regular json_array first
        if (data.is<json_array>()) {
            auto ptr = data.ptr<json_array>();
            return ptr && idx < ptr->size();
        }
        
        // Handle specialized array types
        if (data.is<fl::vector<i16>>()) {
            auto ptr = data.ptr<fl::vector<i16>>();
            return ptr && idx < ptr->size();
        }
        if (data.is<fl::vector<u8>>()) {
            auto ptr = data.ptr<fl::vector<u8>>();
            return ptr && idx < ptr->size();
        }
        if (data.is<fl::vector<float>>()) {
            auto ptr = data.ptr<fl::vector<float>>();
            return ptr && idx < ptr->size();
        }
        return false;
    }
    
    bool contains(const fl::string &key) const FL_NOEXCEPT {
        if (!is_object()) return false;
        auto ptr = data.ptr<json_object>();
        return ptr && ptr->find(key) != ptr->end();
    }

    // Object iteration support (needed for screenmap conversion)
    fl::vector<fl::string> keys() const FL_NOEXCEPT {
        fl::vector<fl::string> result;
        if (is_object()) {
            for (auto it = begin(); it != end(); ++it) {
                auto keyValue = *it;
                result.push_back(keyValue.first);
            }
        }
        return result;
    }
    
    // Backward compatibility method
    fl::vector<fl::string> get_object_keys() const FL_NOEXCEPT { return keys(); }

    // Size methods
    size_t size() const FL_NOEXCEPT {
        SizeVisitor visitor;
        data.visit(visitor);
        return visitor.result;
    }

    // Serialization
    fl::string to_string() const FL_NOEXCEPT;
    
    // Visitor-based serialization helper
    friend struct SerializerVisitor;

    // Custom two-phase JSON parser (PRODUCTION READY)
    // Features:
    //   - Two-phase: validation (zero alloc) + building
    //   - Array lookahead: Direct parsing to typed vectors (uint8, int16, float)
    //   - Zero-copy tokenization with fl::span<const char>
    //   - ~608 bytes stack overhead, recursion depth limit 32
    //   - Identical behavior to parse() (validated with A/B tests)
    static fl::shared_ptr<json_value> parse2(const fl::string &txt) FL_NOEXCEPT;
    static fl::shared_ptr<json_value> parse2(fl::string_view txt) FL_NOEXCEPT;  // Zero-copy version
    static bool parse2_validate_only(const fl::string &txt) FL_NOEXCEPT;  // Phase 1 validation only (for testing)
    static bool parse2_validate_only(fl::string_view txt) FL_NOEXCEPT;  // Zero-copy version (no allocation)

    // Iterator support for objects
    class iterator {
    private:
        json_object::iterator mIter;

    public:
        using iterator_category = fl::forward_iterator_tag;

        iterator() = default;
        iterator(json_object::iterator iter) FL_NOEXCEPT : mIter(iter) {}
        
        // Getter for const iterator conversion
        json_object::iterator get_iter() const FL_NOEXCEPT { return mIter; }
        
        iterator& operator++() FL_NOEXCEPT {
            ++mIter;
            return *this;
        }
        
        iterator operator++(int) FL_NOEXCEPT {
            iterator tmp(*this);
            ++(*this);
            return tmp;
        }
        
        bool operator!=(const iterator& other) const FL_NOEXCEPT {
            return mIter != other.mIter;
        }
        
        bool operator==(const iterator& other) const FL_NOEXCEPT {
            return mIter == other.mIter;
        }
        
        struct KeyValue {
            fl::string first;
            json_value& second;
            
            KeyValue(const fl::string& key, const fl::shared_ptr<json_value>& value_ptr) FL_NOEXCEPT
                : first(key), second(value_ptr ? *value_ptr : get_null_json_value()) {}
        };
        
        KeyValue operator*() const FL_NOEXCEPT {
            return KeyValue(mIter->first, mIter->second);
        }
        
        // Remove operator-> to avoid static variable issues
    };
    
    // Iterator for JSON objects (const version)
    class const_iterator {
    private:
        json_object::const_iterator mIter;
        
    public:
        using iterator_category = fl::forward_iterator_tag;

        const_iterator() = default;
        const_iterator(json_object::const_iterator iter) FL_NOEXCEPT : mIter(iter) {}
        
        // Factory method for conversion from iterator
        static const_iterator from_object_iterator(const iterator& other) FL_NOEXCEPT {
            json_object::const_iterator const_iter(other.get_iter());
            return const_iterator(const_iter);
        }
        
        // Factory method for conversion from Object::iterator
        static const_iterator from_iterator(json_object::const_iterator iter) FL_NOEXCEPT {
            return const_iterator(iter);
        }
        
        const_iterator& operator++() FL_NOEXCEPT {
            ++mIter;
            return *this;
        }
        
        const_iterator operator++(int) FL_NOEXCEPT {
            const_iterator tmp(*this);
            ++(*this);
            return tmp;
        }
        
        bool operator!=(const const_iterator& other) const FL_NOEXCEPT {
            return mIter != other.mIter;
        }
        
        bool operator==(const const_iterator& other) const FL_NOEXCEPT {
            return mIter == other.mIter;
        }
        
        struct KeyValue {
            fl::string first;
            const json_value& second;
            
            KeyValue(const fl::string& key, const fl::shared_ptr<json_value>& value_ptr) FL_NOEXCEPT
                : first(key), second(value_ptr ? *value_ptr : get_null_json_value()) {}
        };
        
        KeyValue operator*() const FL_NOEXCEPT {
            return KeyValue(mIter->first, mIter->second);
        }
        
        // Remove operator-> to avoid static variable issues
    };
};

// Function to get a reference to a static null json_value
json_value& get_null_json_value() FL_NOEXCEPT;

// Visitor to extract a numeric value from a single json_value element
template<typename T>
struct NumericExtractVisitor {
    T result = T(0);

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT { (*this)(value); }

    void operator()(const i64& v) FL_NOEXCEPT { result = static_cast<T>(v); }
    void operator()(const float& v) FL_NOEXCEPT { result = static_cast<T>(v); }
    void operator()(const bool& v) FL_NOEXCEPT { result = static_cast<T>(v ? 1 : 0); }
    // Non-numeric types → zero
    void operator()(const fl::nullptr_t&) FL_NOEXCEPT {}
    void operator()(const fl::string&) FL_NOEXCEPT {}
    void operator()(const json_array&) FL_NOEXCEPT {}
    void operator()(const json_object&) FL_NOEXCEPT {}
    void operator()(const fl::vector<u8>&) FL_NOEXCEPT {}
    void operator()(const fl::vector<i16>&) FL_NOEXCEPT {}
    void operator()(const fl::vector<float>&) FL_NOEXCEPT {}
};

// Visitor to copy array elements into a span<T> with type conversion
template<typename T>
struct CopyToVisitor {
    fl::span<T> dst;
    size_t result;

    explicit CopyToVisitor(fl::span<T> d) FL_NOEXCEPT : dst(d), result(0) {}

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT { (*this)(value); }

    // Packed vectors: element-wise static_cast
    void operator()(const fl::vector<u8>& v) FL_NOEXCEPT { copy_vec(v); }
    void operator()(const fl::vector<i16>& v) FL_NOEXCEPT { copy_vec(v); }
    void operator()(const fl::vector<float>& v) FL_NOEXCEPT { copy_vec(v); }

    // Generic json_array: visitor-based per-element extraction
    void operator()(const json_array& arr) FL_NOEXCEPT {
        size_t n = (arr.size() < dst.size()) ? arr.size() : dst.size();
        for (size_t i = 0; i < n; ++i) {
            const auto& elem = arr[i];
            if (!elem) { dst[i] = T(0); continue; }
            NumericExtractVisitor<T> nv;
            elem->data.visit(nv);
            dst[i] = nv.result;
        }
        result = n;
    }

    // Non-array types: nothing to copy
    void operator()(const fl::nullptr_t&) FL_NOEXCEPT {}
    void operator()(const bool&) FL_NOEXCEPT {}
    void operator()(const i64&) FL_NOEXCEPT {}
    void operator()(const float&) FL_NOEXCEPT {}
    void operator()(const fl::string&) FL_NOEXCEPT {}
    void operator()(const json_object&) FL_NOEXCEPT {}

private:
    template<typename ElemT>
    void copy_vec(const fl::vector<ElemT>& vec) FL_NOEXCEPT {
        size_t n = (vec.size() < dst.size()) ? vec.size() : dst.size();
        for (size_t i = 0; i < n; ++i) {
            dst[i] = static_cast<T>(vec[i]);
        }
        result = n;
    }
};

// Visitor to stream array elements into an output iterator with type conversion.
// Works with fl::back_inserter(container) to append to any container.
template<typename T, typename OutputIt>
struct CopyToOutputIteratorVisitor {
    OutputIt out;
    size_t result;

    explicit CopyToOutputIteratorVisitor(OutputIt o) FL_NOEXCEPT : out(o), result(0) {}

    template<typename U>
    void accept(const U& value) FL_NOEXCEPT { (*this)(value); }

    // Packed vectors: element-wise static_cast
    void operator()(const fl::vector<u8>& v) FL_NOEXCEPT { write_vec(v); }
    void operator()(const fl::vector<i16>& v) FL_NOEXCEPT { write_vec(v); }
    void operator()(const fl::vector<float>& v) FL_NOEXCEPT { write_vec(v); }

    // Generic json_array: visitor-based per-element extraction
    void operator()(const json_array& arr) FL_NOEXCEPT {
        for (size_t i = 0; i < arr.size(); ++i) {
            const auto& elem = arr[i];
            if (!elem) { *out = T(0); ++out; ++result; continue; }
            NumericExtractVisitor<T> nv;
            elem->data.visit(nv);
            *out = nv.result;
            ++out;
            ++result;
        }
    }

    // Non-array types: nothing to write
    void operator()(const fl::nullptr_t&) FL_NOEXCEPT {}
    void operator()(const bool&) FL_NOEXCEPT {}
    void operator()(const i64&) FL_NOEXCEPT {}
    void operator()(const float&) FL_NOEXCEPT {}
    void operator()(const fl::string&) FL_NOEXCEPT {}
    void operator()(const json_object&) FL_NOEXCEPT {}

private:
    template<typename ElemT>
    void write_vec(const fl::vector<ElemT>& vec) FL_NOEXCEPT {
        for (size_t i = 0; i < vec.size(); ++i) {
            *out = static_cast<T>(vec[i]);
            ++out;
        }
        result = vec.size();
    }
};

// Main json class that provides a more fluid and user-friendly interface

} // namespace fl
