from __future__ import annotations

import gc
import os
import threading
import time
from concurrent.futures import ThreadPoolExecutor

import pytest
from inference.core.workflows.prototypes.block import WorkflowBlock
from inference.enterprise.workflows.enterprise_blocks.loader import \
    load_enterprise_blocks
from inference.enterprise.workflows.enterprise_blocks.sinks.event_writer.v1 import \
    EventWriterSinkBlockV1
from inference.enterprise.workflows.enterprise_blocks.sinks.microsoft_sql_server.v1 import \
    MicrosoftSQLServerSinkBlockV1
from inference.enterprise.workflows.enterprise_blocks.sinks.mqtt_writer.v1 import \
    MQTTWriterSinkBlockV1
from inference.enterprise.workflows.enterprise_blocks.sinks.opc_writer.v1 import \
    OPCWriterSinkBlockV1
from inference.enterprise.workflows.enterprise_blocks.sinks.PLC_modbus.v1 import \
    ModbusTCPBlockV1
from inference.enterprise.workflows.enterprise_blocks.sinks.PLCethernetIP.v1 import \
    PLCBlockV1


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_load_enterprise_blocks_basic_order_and_length():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Basic test:\n    - The loader returns a list of classes.\n    - The list has the expected length and ordering of block types.\n    '
    codeflash_return_value = codeflash_wrap(load_enterprise_blocks, 'tests.inference.unit_tests.test_load_enterprise_blocks__unit_test_0', None, 'test_load_enterprise_blocks_basic_order_and_length', 'load_enterprise_blocks', '1', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    blocks = codeflash_output
    expected_order = [OPCWriterSinkBlockV1, MQTTWriterSinkBlockV1, PLCBlockV1, ModbusTCPBlockV1, MicrosoftSQLServerSinkBlockV1, EventWriterSinkBlockV1]

def test_returned_items_are_classes_and_subclasses_of_workflowblock():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Ensure each returned item is a class (type) and is a subclass of WorkflowBlock.\n    This confirms the loader returns block types, not instances or other objects.\n    '
    codeflash_return_value = codeflash_wrap(load_enterprise_blocks, 'tests.inference.unit_tests.test_load_enterprise_blocks__unit_test_0', None, 'test_returned_items_are_classes_and_subclasses_of_workflowblock', 'load_enterprise_blocks', '1', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    blocks = codeflash_output
    for idx, cls in enumerate(blocks):
        pass

def test_instantiation_and_known_initial_state_of_lightweight_blocks():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    "\n    Instantiate the blocks with known constructor signatures (only for those\n    whose constructors are shown in the source). Verify initial internal state.\n    We avoid instantiating PLCBlockV1 because its constructor signature\n    wasn't provided in the source excerpt.\n    "
    opc = OPCWriterSinkBlockV1(background_tasks=None, thread_pool_executor=None)
    mqtt = MQTTWriterSinkBlockV1()
    connected_event = getattr(mqtt, '_connected', None)
    modbus = ModbusTCPBlockV1()
    mssql = MicrosoftSQLServerSinkBlockV1(background_tasks=None, thread_pool_executor=None)
    event_writer = EventWriterSinkBlockV1(background_tasks=None, thread_pool_executor=None)

def test_list_is_fresh_each_call_and_mutations_do_not_persist():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Ensure load_enterprise_blocks returns a new list each time. Mutating the\n    returned list should not affect subsequent calls.\n    '
    codeflash_return_value = codeflash_wrap(load_enterprise_blocks, 'tests.inference.unit_tests.test_load_enterprise_blocks__unit_test_0', None, 'test_list_is_fresh_each_call_and_mutations_do_not_persist', 'load_enterprise_blocks', '1', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    first = codeflash_output
    popped = first.pop(0)
    codeflash_return_value = codeflash_wrap(load_enterprise_blocks, 'tests.inference.unit_tests.test_load_enterprise_blocks__unit_test_0', None, 'test_list_is_fresh_each_call_and_mutations_do_not_persist', 'load_enterprise_blocks', '4', codeflash_loop_index)
    codeflash_output = codeflash_return_value
    second = codeflash_output

def test_large_scale_repeated_calls_and_instantiations_for_stability():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    "\n    Large-scale test to exercise repeated calls and many lightweight instantiations.\n    This ensures the loader is stable and cheap to call many times and that\n    block constructors don't leak or raise intermittently.\n    We use a moderate number of iterations so the test remains fast but still\n    meaningful (stresses up to a few hundred iterations).\n    "
    iterations = 300
    for i in range(iterations):
        codeflash_return_value = codeflash_wrap(load_enterprise_blocks, 'tests.inference.unit_tests.test_load_enterprise_blocks__unit_test_0', None, 'test_large_scale_repeated_calls_and_instantiations_for_stability', 'load_enterprise_blocks', '2_0', codeflash_loop_index)
        codeflash_output = codeflash_return_value
        blocks = codeflash_output
    instances = []
    for i in range(200):
        instances.append(MQTTWriterSinkBlockV1())
        instances.append(ModbusTCPBlockV1())
        instances.append(OPCWriterSinkBlockV1(background_tasks=None, thread_pool_executor=None))