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
import supervision as sv
from inference.core.workflows.core_steps.sinks.roboflow.dataset_upload.v1 import \
    is_prediction_registration_forbidden


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_none_prediction_is_forbidden():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(None)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_none_prediction_is_forbidden', 'is_prediction_registration_forbidden', '0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_empty_detections_is_forbidden():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    empty_xyxy = np.zeros((0, 4), dtype=float)
    detections = sv.Detections(xyxy=empty_xyxy)
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(detections)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_empty_detections_is_forbidden', 'is_prediction_registration_forbidden', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_nonempty_detections_is_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    xyxy = np.array([[0.0, 0.0, 10.0, 10.0]], dtype=float)
    detections = sv.Detections(xyxy=xyxy)
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(detections)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_nonempty_detections_is_allowed', 'is_prediction_registration_forbidden', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_dict_with_top_key_is_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'top': []}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_dict_with_top_key_is_allowed', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_dict_with_predicted_classes_key_is_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'predicted_classes': [1, 2, 3]}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_dict_with_predicted_classes_key_is_allowed', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_dict_missing_both_keys_is_forbidden():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'some_other_key': 123}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_dict_missing_both_keys_is_forbidden', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_top_key_present_but_value_none_still_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'top': None}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_top_key_present_but_value_none_still_allowed', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_predicted_classes_present_but_empty_list_still_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'predicted_classes': []}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_predicted_classes_present_but_empty_list_still_allowed', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_dict_key_name_case_sensitivity_forbidden():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = {'Top': [1, 2, 3]}
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_dict_key_name_case_sensitivity_forbidden', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_unexpected_type_not_dict_nor_detections_is_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    prediction = 42
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(prediction)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_unexpected_type_not_dict_nor_detections_is_allowed', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_detections_len_derived_from_other_fields():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    detections = sv.Detections(xyxy=np.zeros((0, 4), dtype=float), class_id=np.array([], dtype=int))
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(detections)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_detections_len_derived_from_other_fields', 'is_prediction_registration_forbidden', '1', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_large_number_of_detections_allowed():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    large_xyxy = np.zeros((1000, 4), dtype=float)
    detections = sv.Detections(xyxy=large_xyxy)
    _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(detections)
    _call__bound__arguments.apply_defaults()
    codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_large_number_of_detections_allowed', 'is_prediction_registration_forbidden', '2', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
    codeflash_output = codeflash_return_value

def test_many_dicts_in_loop_consistent_behavior():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    allowed = {'top': [0]}
    forbidden = {'foo': 'bar'}
    results_allowed = []
    results_forbidden = []
    for _ in range(1000):
        _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(allowed)
        _call__bound__arguments.apply_defaults()
        codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_many_dicts_in_loop_consistent_behavior', 'is_prediction_registration_forbidden', '4_0', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)
        _call__bound__arguments = inspect.signature(is_prediction_registration_forbidden).bind(forbidden)
        _call__bound__arguments.apply_defaults()
        codeflash_return_value = codeflash_wrap(is_prediction_registration_forbidden, 'tests.inference.unit_tests.test_is_prediction_registration_forbidden__unit_test_0', None, 'test_many_dicts_in_loop_consistent_behavior', 'is_prediction_registration_forbidden', '4_3', codeflash_loop_index, *_call__bound__arguments.args, **_call__bound__arguments.kwargs)