from __future__ import annotations

import gc
import os
import time

import pytest
from inference.core.entities.responses.workflows import WorkflowErrorResponse
from inference.core.interfaces.http.error_handlers import \
    _build_step_execution_error_response
from inference.core.workflows.errors import StepExecutionError
from inference.core.workflows.errors import \
    WorkflowBlockError as WorkflowBlockErrorModel


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_build_response_basic():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    inner_exc = ValueError('inner')
    err = StepExecutionError('block-1', 'python', ['trace A'], 'Public message', 'ctx-1', inner_exc)
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_0', None, 'test_build_response_basic', '_build_step_execution_error_response', '2', codeflash_loop_index, err)
    codeflash_output = codeflash_return_value
    resp = codeflash_output
    block_err = resp.blocks_errors[0]

def test_inner_none_and_empty_strings():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    err = StepExecutionError('b-empty', 't-empty', None, '', '', None)
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_0', None, 'test_inner_none_and_empty_strings', '_build_step_execution_error_response', '1', codeflash_loop_index, err)
    codeflash_output = codeflash_return_value
    resp = codeflash_output
    block_err = resp.blocks_errors[0]

def test_special_characters_and_non_string_ids():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    inner = RuntimeError('🔥error\nline2')
    err = StepExecutionError(123, None, {'trace': 'val'}, 'pub: ©', '\nctx\t', inner)
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_0', None, 'test_special_characters_and_non_string_ids', '_build_step_execution_error_response', '2', codeflash_loop_index, err)
    codeflash_output = codeflash_return_value
    resp = codeflash_output
    block_err = resp.blocks_errors[0]

def test_large_scale_many_consecutive_calls():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    N = 1000
    last_resp = None
    for i in range(N):
        inner = ValueError(f'err-{i}')
        err = StepExecutionError(f'b{i}', f't{i}', None, f'msg{i}', f'ctx{i}', inner)
        codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_0', None, 'test_large_scale_many_consecutive_calls', '_build_step_execution_error_response', '2_2', codeflash_loop_index, err)
        codeflash_output = codeflash_return_value
        last_resp = codeflash_output

def test_large_block_traceback_payload():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    big_tb = list(range(1000))
    inner = RuntimeError('bigtrace')
    err = StepExecutionError('big-block', 'big-type', big_tb, 'big-msg', 'big-ctx', inner)
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_0', None, 'test_large_block_traceback_payload', '_build_step_execution_error_response', '3', codeflash_loop_index, err)
    codeflash_output = codeflash_return_value
    resp = codeflash_output