from __future__ import annotations

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

import dill as pickle
import pytest
from inference.core.workflows.core_steps.sinks.slack.notification.v1 import \
    BlockManifest


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_structure_and_values():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Basic test: ensure the method returns a dict with the exact expected keys\n    and the expected constant values/types.\n    '
    _call__bound__arguments = inspect.signature(BlockManifest.get_air_gapped_availability).bind()
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(BlockManifest.get_air_gapped_availability, 'tests.inference.unit_tests.test_get_air_gapped_availability__unit_test_0', None, 'test_basic_structure_and_values', 'get_air_gapped_availability', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    result = codeflash_output

def test_returns_distinct_mutable_dicts_each_call():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Edge test: ensure each call returns a fresh dict instance (so callers can\n    mutate it safely without affecting other callers). Also verify equality of\n    values across calls.\n    '
    _call__bound__arguments = inspect.signature(BlockManifest.get_air_gapped_availability).bind()
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(BlockManifest.get_air_gapped_availability, 'tests.inference.unit_tests.test_get_air_gapped_availability__unit_test_0', None, 'test_returns_distinct_mutable_dicts_each_call', 'get_air_gapped_availability', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    first = codeflash_output
    _call__bound__arguments = inspect.signature(BlockManifest.get_air_gapped_availability).bind()
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(BlockManifest.get_air_gapped_availability, 'tests.inference.unit_tests.test_get_air_gapped_availability__unit_test_0', None, 'test_returns_distinct_mutable_dicts_each_call', 'get_air_gapped_availability', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    second = codeflash_output
    first['available'] = True

def test_json_serializable_and_roundtrip_consistent():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Edge test: the returned dict should be JSON serializable and produce the\n    same content after a JSON round-trip.\n    '
    _call__bound__arguments = inspect.signature(BlockManifest.get_air_gapped_availability).bind()
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(BlockManifest.get_air_gapped_availability, 'tests.inference.unit_tests.test_get_air_gapped_availability__unit_test_0', None, 'test_json_serializable_and_roundtrip_consistent', 'get_air_gapped_availability', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    result = codeflash_output
    json_text = json.dumps(result)
    roundtrip = json.loads(json_text)

def test_repeated_calls_consistency_large_scale():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Large-scale test: call the method many times (1000) to ensure consistent\n    behavior over many invocations and that there are no shared mutable\n    structures across calls.\n    '
    N = 1000
    results = [BlockManifest.get_air_gapped_availability() for _ in range(N)]
    first = results[0]
    ids = [id(r) for r in results]
    results[0]['reason'] = 'mutated'

def test_callable_via_getattr_and_no_side_effects():
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    '\n    Basic/edge test: ensure the method can be accessed via getattr and that\n    calling it leaves the class state unchanged (no attributes added/modified).\n    '
    before_attrs = set(dir(BlockManifest))
    func = getattr(BlockManifest, 'get_air_gapped_availability')
    out = func()
    after_attrs = set(dir(BlockManifest))