from __future__ import annotations

import gc
import os
import time

import pytest
from inference.core.workflows.core_steps.models.foundation.qwen3_5vl.v1 import \
    BlockManifest
from inference.core.workflows.execution_engine.entities.base import \
    OutputDefinition
from inference.core.workflows.execution_engine.entities.types import \
    DICTIONARY_KIND


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 test_basic_functionality_describe_outputs_structure():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Basic test:\n    - Ensure describe_outputs returns a list with one OutputDefinition.\n    - Check that the returned element has the expected name, kind, and description.\n    '
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_basic_functionality_describe_outputs_structure', 'describe_outputs', '1', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    outputs = codeflash_output
    out = outputs[0]
    kind = getattr(out, 'kind')
    desc = getattr(out, 'description')
    _ = (out.name, out.kind, out.description)

def test_instance_get_actual_outputs_matches_classmethod():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    "\n    Verify that an instance's get_actual_outputs delegates to the classmethod.\n    Construct a real BlockManifest instance using the actual constructor (pydantic model).\n    "
    instance = BlockManifest(type='roboflow_core/qwen3_5vl@v1', name='test_block')
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_instance_get_actual_outputs_matches_classmethod', 'describe_outputs', '2', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    class_outputs = codeflash_output
    instance_outputs = instance.get_actual_outputs()
    co = class_outputs[0]
    io = instance_outputs[0]

def test_outputs_are_fresh_between_calls_and_independent_when_mutated():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Ensure that each call to describe_outputs returns a fresh list and fresh OutputDefinition instances.\n    Mutating the returned list from one call must not affect outputs from subsequent calls.\n    '
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_outputs_are_fresh_between_calls_and_independent_when_mutated', 'describe_outputs', '1', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    first = codeflash_output
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_outputs_are_fresh_between_calls_and_independent_when_mutated', 'describe_outputs', '3', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    second = codeflash_output
    extra = OutputDefinition(name='extra', kind=[DICTIONARY_KIND], description='extra')
    first.append(extra)
    original_kind = list(first[0].kind)
    first[0].kind.append('bogus_kind')
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_outputs_are_fresh_between_calls_and_independent_when_mutated', 'describe_outputs', '9', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    after_mutation = codeflash_output
    first[0].kind[:] = original_kind

def test_large_scale_repeated_calls_produce_independent_objects_and_consistent_content():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Large-scale test:\n    - Call describe_outputs 1000 times.\n    - Ensure each returned list and its contained OutputDefinition are distinct objects (no accidental reuse).\n    - Ensure content (name and kind) remains consistent every time.\n    This validates scalability up to the requested number of iterations.\n    '
    iterations = 1000
    list_ids = set()
    element_ids = set()
    names = set()
    kinds_seen = set()
    for _ in range(iterations):
        codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_large_scale_repeated_calls_produce_independent_objects_and_consistent_content', 'describe_outputs', '6_0', codeflash_loop_index)
        codeflash_output = codeflash_return_value
        outs = codeflash_output
        lid = id(outs)
        eid = id(outs[0])
        list_ids.add(lid)
        element_ids.add(eid)
        names.add(outs[0].name)
        kinds_seen.add(tuple(outs[0].kind))