from __future__ import annotations

import gc
import inspect
import os
import time
from pathlib import Path

import dill as pickle
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,
                                             WorkflowBlockError)


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}######!')
    iteration = os.environ['CODEFLASH_TEST_ITERATION']
    with Path('{codeflash_run_tmp_dir_client_side}', f'test_return_values_{iteration}.bin').open('ab') as f:
        pickled_values = pickle.dumps((args, kwargs, exception)) if exception else pickle.dumps((args, kwargs, return_value))
        _test_name = f"{codeflash_test_module_name}:{(codeflash_test_class_name + '.' if codeflash_test_class_name else '')}{codeflash_test_name}:{codeflash_function_name}:{codeflash_line_id}".encode('ascii')
        f.write(len(_test_name).to_bytes(4, byteorder='big'))
        f.write(_test_name)
        f.write(codeflash_duration.to_bytes(8, byteorder='big'))
        f.write(len(pickled_values).to_bytes(4, byteorder='big'))
        f.write(pickled_values)
        f.write(codeflash_loop_index.to_bytes(8, byteorder='big'))
        f.write(len(invocation_id).to_bytes(4, byteorder='big'))
        f.write(invocation_id.encode('ascii'))
    if exception:
        raise exception
    return return_value

def test_basic_step_execution_error_response():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test basic functionality with a simple StepExecutionError.'
    error = StepExecutionError(block_id='test_block', block_type='test_type', public_message='Test error message', context='test_context')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_basic_step_execution_error_response', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_response_has_blocks_errors_list():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that the response contains a blocks_errors list with one entry.'
    error = StepExecutionError(block_id='block_123', block_type='code_executor', public_message='Execution failed', context='execution_context')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_response_has_blocks_errors_list', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_block_error_details():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that block error details are correctly populated.'
    error = StepExecutionError(block_id='my_block', block_type='my_type', public_message='Error occurred', context='my_context')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_block_error_details', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output
    block_error = response.blocks_errors[0]

def test_inner_error_handling_with_none():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test handling when inner_error is None.'
    error = StepExecutionError(block_id='block_id', block_type='block_type', public_message='Public message', context='context')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_inner_error_handling_with_none', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_inner_error_handling_with_exception():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test handling when inner_error is a real exception.'
    inner_exception = ValueError('Invalid value provided')
    error = StepExecutionError(block_id='block_id', block_type='block_type', public_message='Public message', context='context', inner_error=inner_exception)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_inner_error_handling_with_exception', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_response_message_field_populated():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that the response message field matches error public_message.'
    public_msg = 'This is a public error message'
    error = StepExecutionError(block_id='bid', block_type='btype', public_message=public_msg, context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_response_message_field_populated', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_empty_string_block_id():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with empty string for block_id.'
    error = StepExecutionError(block_id='', block_type='type', public_message='msg', context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_empty_string_block_id', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_empty_string_block_type():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with empty string for block_type.'
    error = StepExecutionError(block_id='id', block_type='', public_message='msg', context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_empty_string_block_type', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_empty_string_messages():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with empty strings for public_message and context.'
    error = StepExecutionError(block_id='id', block_type='type', public_message='', context='')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_empty_string_messages', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_special_characters_in_messages():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test handling of special characters in messages.'
    special_chars = 'Error: \n\t\r\'"\\<>&'
    error = StepExecutionError(block_id='id', block_type='type', public_message=special_chars, context=special_chars)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_special_characters_in_messages', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_unicode_characters_in_messages():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test handling of Unicode characters.'
    unicode_msg = 'エラー: 错误 🚀 Ошибка'
    error = StepExecutionError(block_id='id', block_type='type', public_message=unicode_msg, context=unicode_msg)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_unicode_characters_in_messages', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_very_long_block_id():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with very long block_id.'
    long_id = 'x' * 10000
    error = StepExecutionError(block_id=long_id, block_type='type', public_message='msg', context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_very_long_block_id', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_very_long_message():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with very long message.'
    long_msg = 'Error: ' + 'detail ' * 5000
    error = StepExecutionError(block_id='id', block_type='type', public_message=long_msg, context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_very_long_message', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_with_block_traceback_none():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test when block_traceback is explicitly None.'
    error = StepExecutionError(block_id='id', block_type='type', block_traceback=None, public_message='msg', context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_with_block_traceback_none', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_multiple_levels_of_exception_nesting():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with deeply nested exceptions.'
    inner = ValueError('Inner error')
    middle = RuntimeError('Middle error')
    middle.__cause__ = inner
    outer = TypeError('Outer error')
    outer.__cause__ = middle
    error = StepExecutionError(block_id='id', block_type='type', public_message='msg', context='ctx', inner_error=outer)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_multiple_levels_of_exception_nesting', '_build_step_execution_error_response', '7', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_custom_exception_with_no_message():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with custom exception that has no message.'
    custom_exception = Exception()
    error = StepExecutionError(block_id='id', block_type='type', public_message='msg', context='ctx', inner_error=custom_exception)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_custom_exception_with_no_message', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_whitespace_only_strings():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with whitespace-only strings.'
    error = StepExecutionError(block_id='   ', block_type='\t\t', public_message='   \n\n   ', context='\r\n')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_whitespace_only_strings', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_response_error_type_always_step_execution_error():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that error_type field always shows StepExecutionError class name.'
    error1 = StepExecutionError(block_id='id1', block_type='type1', public_message='msg1', context='ctx1')
    error2 = StepExecutionError(block_id='id2', block_type='type2', public_message='msg2', context='ctx2', inner_error=ValueError('inner'))
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error1)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_response_error_type_always_step_execution_error', '_build_step_execution_error_response', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response1 = codeflash_output
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error2)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_response_error_type_always_step_execution_error', '_build_step_execution_error_response', '5', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response2 = codeflash_output

def test_response_property_name_always_python_code():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    "Test that property_name is always set to 'Python code'."
    error = StepExecutionError(block_id='id', block_type='type', public_message='msg', context='ctx')
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_response_property_name_always_python_code', '_build_step_execution_error_response', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_large_scale_message_concatenation():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with very large concatenated messages.'
    base_msg = 'Error detail: '
    iterations = 1000
    large_msg = base_msg + ('x' * 100 + ' ') * iterations
    error = StepExecutionError(block_id='id', block_type='type', public_message=large_msg, context=large_msg)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_large_scale_message_concatenation', '_build_step_execution_error_response', '5', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_large_scale_with_many_exception_args():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test with exception containing many arguments.'
    many_args = tuple((f'arg_{i}' for i in range(1000)))
    exception_obj = Exception(*many_args)
    error = StepExecutionError(block_id='id', block_type='type', public_message='msg', context='ctx', inner_error=exception_obj)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_large_scale_with_many_exception_args', '_build_step_execution_error_response', '4', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output

def test_repeated_error_responses_consistency():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that calling the function repeatedly produces consistent results.'
    error = StepExecutionError(block_id='consistent_id', block_type='consistent_type', public_message='consistent message', context='consistent context')
    responses = [_build_step_execution_error_response(error) for _ in range(1000)]
    first_response = responses[0]
    for i, response in enumerate(responses[1:], start=1):
        pass

def test_large_scale_with_different_exception_types():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test processing 1000 different exception types.'
    exception_types = [ValueError('value error'), TypeError('type error'), RuntimeError('runtime error'), KeyError('key error'), IndexError('index error'), AttributeError('attribute error'), ZeroDivisionError('zero division error'), FileNotFoundError('file not found'), PermissionError('permission error'), OSError('os error')]
    errors = []
    for i in range(1000):
        exception = exception_types[i % len(exception_types)]
        errors.append(StepExecutionError(block_id=f'id_{i}', block_type=f'type_{i}', public_message=f'msg_{i}', context=f'ctx_{i}', inner_error=exception))
    responses = [_build_step_execution_error_response(error) for error in errors]
    for i, response in enumerate(responses):
        pass

def test_stress_test_with_maximum_length_strings():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Stress test with maximum-length strings across all fields.'
    max_id = 'a' * 100000
    max_type = 'b' * 100000
    max_msg = 'c' * 100000
    max_ctx = 'd' * 100000
    error = StepExecutionError(block_id=max_id, block_type=max_type, public_message=max_msg, context=max_ctx)
    _call__bound__arguments = inspect.signature(_build_step_execution_error_response).bind(error)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_build_step_execution_error_response, 'tests.inference.unit_tests.test__build_step_execution_error_response__unit_test_1', None, 'test_stress_test_with_maximum_length_strings', '_build_step_execution_error_response', '6', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    response = codeflash_output