from __future__ import annotations

import gc
import os
import time

import pytest
from inference.core.workflows.core_steps.models.foundation.glm_ocr.v1 import \
    BlockManifest
from inference.core.workflows.execution_engine.entities.base import \
    OutputDefinition
from inference.core.workflows.execution_engine.entities.types import \
    STRING_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_describe_outputs_structure():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_basic_describe_outputs_structure', 'describe_outputs', '0', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    outputs = codeflash_output
    out = outputs[0]

def test_describe_outputs_kind_is_a_list_and_contains_string_kind():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_describe_outputs_kind_is_a_list_and_contains_string_kind', 'describe_outputs', '0', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    outputs = codeflash_output
    out = outputs[0]

def test_get_actual_outputs_on_instance_returns_same_structure():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    manifest_instance = BlockManifest(type='roboflow_core/glm_ocr@v1', name='unit-test')
    instance_outputs = manifest_instance.get_actual_outputs()
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_get_actual_outputs_on_instance_returns_same_structure', 'describe_outputs', '2', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    class_outputs = codeflash_output
    inst_out = instance_outputs[0]
    cls_out = class_outputs[0]

def test_describe_outputs_returns_new_instances_each_call_and_isolation():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_describe_outputs_returns_new_instances_each_call_and_isolation', 'describe_outputs', '0', 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_describe_outputs_returns_new_instances_each_call_and_isolation', 'describe_outputs', '2', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    second = codeflash_output
    original_desc = second[0].description
    first[0].description = 'temporarily modified description for test'
    codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_describe_outputs_returns_new_instances_each_call_and_isolation', 'describe_outputs', '6', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    fresh = codeflash_output

def test_describe_outputs_is_stable_over_many_calls_and_produces_consistent_values():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    iterations = 1000
    seen = []
    for _ in range(iterations):
        codeflash_return_value = codeflash_wrap(BlockManifest.describe_outputs, 'tests.inference.unit_tests.test_describe_outputs__unit_test_0', None, 'test_describe_outputs_is_stable_over_many_calls_and_produces_consistent_values', 'describe_outputs', '2_0', codeflash_loop_index)
        out = codeflash_return_value
        seen.append((out.name, out.description, tuple(out.kind)))
    first_tuple = seen[0]
    for idx, t in enumerate(seen):
        pass