from __future__ import annotations

import gc
import os
import time

import pytest
from inference.core.workflows.core_steps.common.query_language.introspection.core import \
    _get_property_name_options


def codeflash_wrap(codeflash_wrapped, codeflash_test_module_name, codeflash_test_class_name, codeflash_test_name, codeflash_function_name, codeflash_line_id, codeflash_loop_index, *args, **kwargs):
    test_id = f'{codeflash_test_module_name}:{codeflash_test_class_name}:{codeflash_test_name}:{codeflash_line_id}:{codeflash_loop_index}'
    if not hasattr(codeflash_wrap, 'index'):
        codeflash_wrap.index = {}
    if test_id in codeflash_wrap.index:
        codeflash_wrap.index[test_id] += 1
    else:
        codeflash_wrap.index[test_id] = 0
    codeflash_test_index = codeflash_wrap.index[test_id]
    invocation_id = f'{codeflash_line_id}_{codeflash_test_index}'
    test_stdout_tag = f"{codeflash_test_module_name}:{(codeflash_test_class_name + '.' if codeflash_test_class_name else '')}{codeflash_test_name}:{codeflash_function_name}:{codeflash_loop_index}:{invocation_id}"
    print(f'!$######{test_stdout_tag}######$!')
    exception = None
    gc.disable()
    try:
        counter = time.perf_counter_ns()
        return_value = codeflash_wrapped(*args, **kwargs)
        codeflash_duration = time.perf_counter_ns() - counter
    except Exception as e:
        codeflash_duration = time.perf_counter_ns() - counter
        exception = e
    gc.enable()
    print(f'!######{test_stdout_tag}:{codeflash_duration}######!')
    if exception:
        raise exception
    return return_value

def _ref_to_def_name(schema: dict, ref_key: str='$ref') -> object:
    """Extract definition name from a JSON Schema object's $ref (e.g. {'$ref': '#/$defs/Foo'} -> 'Foo')."""
    ref = schema.get(ref_key)
    if ref is None:
        return None
    return ref.split('/')[-1]

class TestGetPropertyNameOptionsBasic:
    """Basic tests for fundamental functionality."""

    def test_empty_type_definition_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Empty type_definition dict should return None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_empty_type_definition_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_no_properties_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Type definition with no properties key returns None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_no_properties_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {'other_key': 'value'}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_properties_none_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Type definition with properties set to None returns None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_properties_none_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {'properties': None}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_no_property_name_key_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Properties dict without property_name key returns None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_no_property_name_key_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {'properties': {'other_prop': {}}}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_property_name_empty_dict_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'property_name key with empty dict returns None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_property_name_empty_dict_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {'properties': {'property_name': {}}}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_direct_enum_in_property_name(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Direct enum in property_name schema is returned as list.'
        type_def = {'properties': {'property_name': {'enum': ['option1', 'option2', 'option3']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_direct_enum_in_property_name', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_direct_enum_with_single_value(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Direct enum with single value is returned as list with one element.'
        type_def = {'properties': {'property_name': {'enum': ['single_option']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_direct_enum_with_single_value', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_resolved_from_defs(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Property_name with $ref is resolved from defs dict.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/PropertyNameEnum'}}}
        defs = {'PropertyNameEnum': {'enum': ['value1', 'value2']}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_ref_resolved_from_defs', '_get_property_name_options', '3', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_not_in_defs_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        "$ref that doesn't exist in defs returns None."
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/NonExistent'}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_ref_not_in_defs_returns_none', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_exists_but_no_enum_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        '$ref exists in defs but has no enum field returns None.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/PropertyNameEnum'}}}
        defs = {'PropertyNameEnum': {'type': 'string'}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_ref_exists_but_no_enum_returns_none', '_get_property_name_options', '3', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_is_converted_to_list(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum tuple is converted to list (immutable to mutable).'
        type_def = {'properties': {'property_name': {'enum': ('a', 'b', 'c')}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsBasic', 'test_enum_is_converted_to_list', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

class TestGetPropertyNameOptionsEdgeCases:
    """Edge case tests for unusual or boundary conditions."""

    def test_property_name_none_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'property_name value of None returns None.'
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_property_name_none_returns_none', '_get_property_name_options', '1', codeflash_loop_index, {'properties': {'property_name': None}}, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_property_name_empty_enum_list(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Empty enum list returns empty list.'
        type_def = {'properties': {'property_name': {'enum': []}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_property_name_empty_enum_list', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_mixed_types(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum with mixed data types (strings, numbers, etc) is returned as-is.'
        type_def = {'properties': {'property_name': {'enum': ['string', 42, 3.14, True, None]}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_enum_with_mixed_types', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_special_characters(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum values with special characters are preserved.'
        type_def = {'properties': {'property_name': {'enum': ['value-1', 'value_2', 'value.3', 'value@4']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_enum_with_special_characters', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_unicode_values(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum with unicode characters is preserved.'
        type_def = {'properties': {'property_name': {'enum': ['café', 'naïve', '日本語']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_enum_with_unicode_values', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_empty_strings(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum containing empty strings is handled correctly.'
        type_def = {'properties': {'property_name': {'enum': ['', 'non-empty', '']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_enum_with_empty_strings', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_with_complex_path(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        '$ref with nested path components is resolved correctly.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/nested/component/TypeName'}}}
        defs = {'TypeName': {'enum': ['a', 'b']}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_ref_with_complex_path', '_get_property_name_options', '3', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_defined_but_none_returns_none(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        '$ref exists in defs with None value returns None.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/PropertyNameEnum'}}}
        defs = {'PropertyNameEnum': None}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_ref_defined_but_none_returns_none', '_get_property_name_options', '3', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_in_property_name_takes_precedence_over_missing_ref(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum in property_name schema is used even when $ref exists.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/PropertyNameEnum', 'enum': ['direct_enum']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_enum_in_property_name_takes_precedence_over_missing_ref', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_properties_with_extra_keys(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        "Properties dict with extra keys doesn't affect result."
        type_def = {'properties': {'property_name': {'enum': ['value']}, 'other_property': {'enum': ['other_value']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_properties_with_extra_keys', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_defs_with_many_unused_entries(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        "Large defs dict with unused entries doesn't affect result."
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/TargetEnum'}}}
        defs = {f'UnusedEnum{i}': {'enum': [f'unused{i}']} for i in range(100)}
        defs['TargetEnum'] = {'enum': ['target_value']}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_defs_with_many_unused_entries', '_get_property_name_options', '4', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_case_sensitive_ref_matching(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        '$ref matching is case-sensitive.'
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/PropertyNameEnum'}}}
        defs = {'propertynameenum': {'enum': ['wrong']}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsEdgeCases', 'test_case_sensitive_ref_matching', '_get_property_name_options', '3', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

class TestGetPropertyNameOptionsLargeScale:
    """Large-scale tests for performance and scalability."""

    def test_large_enum_list(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum with 1000 values is handled correctly.'
        enum_values = [f'option_{i}' for i in range(1000)]
        type_def = {'properties': {'property_name': {'enum': enum_values}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_large_enum_list', '_get_property_name_options', '3', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_large_defs_dict_with_ref(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Large defs dict with $ref resolution.'
        defs = {f'Enum{i}': {'enum': [f'val{i}']} for i in range(1000)}
        defs['TargetEnum'] = {'enum': ['target1', 'target2', 'target3']}
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/TargetEnum'}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_large_defs_dict_with_ref', '_get_property_name_options', '4', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_deeply_nested_properties(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Type definition with deeply nested structure.'
        type_def = {'properties': {'property_name': {'enum': ['a', 'b', 'c']}, 'level1': {'properties': {'level2': {'properties': {'level3': {'enum': ['should_not_affect']}}}}}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_deeply_nested_properties', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_very_long_strings(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum with very long string values.'
        long_value = 'x' * 10000
        type_def = {'properties': {'property_name': {'enum': [long_value, 'short']}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_enum_with_very_long_strings', '_get_property_name_options', '3', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_ref_resolution_with_many_defs_entries(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        '$ref resolution when defs has thousands of entries.'
        defs = {f'Definition{i}': {'type': 'string'} for i in range(1000)}
        defs['SpecialEnum'] = {'enum': ['special1', 'special2']}
        type_def = {'properties': {'property_name': {'$ref': '#/$defs/SpecialEnum'}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_ref_resolution_with_many_defs_entries', '_get_property_name_options', '4', codeflash_loop_index, type_def, defs)
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_multiple_calls_with_same_defs(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Multiple function calls with same defs dict structure.'
        base_defs = {f'Enum{i}': {'enum': [f'val{i}']} for i in range(500)}
        for idx in range(10):
            type_def = {'properties': {'property_name': {'$ref': f'#/$defs/Enum{idx}'}}}
            codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_multiple_calls_with_same_defs', '_get_property_name_options', '2_1', codeflash_loop_index, type_def, base_defs)
            codeflash_output = codeflash_return_value
            result = codeflash_output

    def test_properties_dict_with_many_keys(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Properties dict with many unused keys.'
        properties = {'property_name': {'enum': ['target']}}
        for i in range(999):
            properties[f'unused_prop_{i}'] = {'type': 'string'}
        type_def = {'properties': properties}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_properties_dict_with_many_keys', '_get_property_name_options', '4', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output

    def test_enum_with_duplicate_values(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Enum with many duplicate values.'
        type_def = {'properties': {'property_name': {'enum': ['value'] * 1000}}}
        codeflash_return_value = codeflash_wrap(_get_property_name_options, 'tests.inference.unit_tests.test__get_property_name_options__unit_test_1', 'TestGetPropertyNameOptionsLargeScale', 'test_enum_with_duplicate_values', '_get_property_name_options', '2', codeflash_loop_index, type_def, {})
        codeflash_output = codeflash_return_value
        result = codeflash_output