from __future__ import annotations

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

import dill as pickle
import numpy as np
import pytest
from inference.core.interfaces.camera.test_pattern_producer import \
    _generate_grid_colors


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
GRID_COLS = 16
GRID_ROWS = 9

def test_basic_returns_shape_dtype_and_range():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    seed = 0
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(seed)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_basic_returns_shape_dtype_and_range', '_generate_grid_colors', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    grid = codeflash_output
    min_val = int(grid.min())
    max_val = int(grid.max())

def test_determinism_same_seed_and_distinct_objects():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    seed = 12345
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(seed)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_determinism_same_seed_and_distinct_objects', '_generate_grid_colors', '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(_generate_grid_colors).bind(seed)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_determinism_same_seed_and_distinct_objects', '_generate_grid_colors', '3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    second = codeflash_output

def test_mutating_returned_array_does_not_change_future_calls():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    seed = 42
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(seed)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_mutating_returned_array_does_not_change_future_calls', '_generate_grid_colors', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    original = codeflash_output
    preserved_value = int(original[0, 0, 0])
    original[0, 0, 0] = 99
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(seed)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_mutating_returned_array_does_not_change_future_calls', '_generate_grid_colors', '5', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    regenerated = codeflash_output

def test_different_seeds_produce_different_grids():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(0)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_different_seeds_produce_different_grids', '_generate_grid_colors', '0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    a = codeflash_output
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(1)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_different_seeds_produce_different_grids', '_generate_grid_colors', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    b = codeflash_output

def test_negative_and_large_seed_values_are_supported_and_deterministic():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    seeds = [-1, 2 ** 31 - 1]
    results = {}
    for s in seeds:
        _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(s)
        _call__bound__arguments.apply_defaults()
        codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_negative_and_large_seed_values_are_supported_and_deterministic', '_generate_grid_colors', '2_0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
        codeflash_output = codeflash_return_value
        first = codeflash_output
        _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(s)
        _call__bound__arguments.apply_defaults()
        codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_negative_and_large_seed_values_are_supported_and_deterministic', '_generate_grid_colors', '2_5', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
        codeflash_output = codeflash_return_value
        second = codeflash_output
        results[s] = first

def test_all_cells_not_identical():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(7)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_all_cells_not_identical', '_generate_grid_colors', '0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value
    grid = codeflash_output
    flat = grid.reshape(-1, 3)
    unique_colors = {tuple(row.tolist()) for row in flat}

def test_many_seeds_produce_highly_diverse_grids():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    n = 1000
    seen = set()
    for s in range(n):
        _call__bound__arguments = inspect.signature(_generate_grid_colors).bind(s)
        _call__bound__arguments.apply_defaults()
        codeflash_return_value = codeflash_wrap(_generate_grid_colors, 'tests.inference.unit_tests.test__generate_grid_colors__unit_test_0', None, 'test_many_seeds_produce_highly_diverse_grids', '_generate_grid_colors', '2_0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
        codeflash_output = codeflash_return_value
        grid = codeflash_output
        seen.add(grid.tobytes())
    unique_count = len(seen)