from __future__ import annotations

import gc
import os
import time

import cv2 as cv
import numpy as np
import pytest
import supervision as sv
from inference.core.workflows.core_steps.classical_cv.mask_area_measurement.v1 import \
    get_detection_area


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_get_detection_area_with_bounding_box_only():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation using bounding box when no mask is available.'
    xyxy = np.array([[10.0, 20.0, 50.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_bounding_box_only', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_simple_circular_mask():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation using a circular segmentation mask.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    center = (50, 50)
    radius = 30
    cv.circle(mask, center, radius, 255, -1)
    mask_array = np.array([mask])
    xyxy = np.array([[20.0, 20.0, 80.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_simple_circular_mask', 'get_detection_area', '8', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output
    expected_area = np.pi * radius ** 2

def test_get_detection_area_with_rectangular_mask():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation using a rectangular segmentation mask.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    mask[20:80, 30:70] = 255
    mask_array = np.array([mask])
    xyxy = np.array([[0.0, 0.0, 100.0, 100.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_rectangular_mask', 'get_detection_area', '6', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_fallback_to_bbox_when_mask_empty():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that bbox is used as fallback when mask contains no contours.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    mask_array = np.array([mask])
    xyxy = np.array([[10.0, 20.0, 50.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_fallback_to_bbox_when_mask_empty', 'get_detection_area', '5', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_multiple_detections_different_indices():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation for different detection indices.'
    xyxy = np.array([[0.0, 0.0, 100.0, 100.0], [10.0, 10.0, 60.0, 60.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0, 1]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_multiple_detections_different_indices', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area_0 = codeflash_output
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_multiple_detections_different_indices', 'get_detection_area', '5', codeflash_loop_index, detections, 1)
    codeflash_output = codeflash_return_value
    area_1 = codeflash_output

def test_get_detection_area_with_zero_width_bbox():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation when bounding box has zero width.'
    xyxy = np.array([[50.0, 20.0, 50.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_zero_width_bbox', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_zero_height_bbox():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation when bounding box has zero height.'
    xyxy = np.array([[10.0, 50.0, 50.0, 50.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_zero_height_bbox', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_very_small_bbox():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with very small bounding box.'
    xyxy = np.array([[0.5, 0.5, 1.5, 1.5]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_very_small_bbox', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_very_large_bbox():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with very large bounding box.'
    xyxy = np.array([[0.0, 0.0, 10000.0, 10000.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_very_large_bbox', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_mask_zero_area_contour():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that function falls back to bbox when mask contour has zero area.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    cv.line(mask, (10, 10), (50, 50), 255, 1)
    mask_array = np.array([mask])
    xyxy = np.array([[10.0, 20.0, 50.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_mask_zero_area_contour', 'get_detection_area', '6', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_float_bbox_coordinates():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with floating point bounding box coordinates.'
    xyxy = np.array([[10.5, 20.3, 50.7, 80.9]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_float_bbox_coordinates', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output
    expected = (50.7 - 10.5) * (80.9 - 20.3)

def test_get_detection_area_with_negative_bbox_coordinates():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with negative bounding box coordinates.'
    xyxy = np.array([[-50.0, -30.0, 50.0, 70.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_negative_bbox_coordinates', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_single_pixel_mask():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with a mask containing only a single pixel.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    mask[50, 50] = 255
    mask_array = np.array([mask])
    xyxy = np.array([[0.0, 0.0, 100.0, 100.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_single_pixel_mask', 'get_detection_area', '6', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_complex_mask_shape():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with a complex, non-convex mask shape.'
    mask = np.zeros((200, 200), dtype=np.uint8)
    pts = np.array([[100, 20], [130, 70], [180, 100], [130, 130], [100, 180], [70, 130], [20, 100], [70, 70]], dtype=np.int32)
    cv.fillPoly(mask, [pts], 255)
    mask_array = np.array([mask])
    xyxy = np.array([[0.0, 0.0, 200.0, 200.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_complex_mask_shape', 'get_detection_area', '7', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_inverted_bbox():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation when bounding box has inverted coordinates.'
    xyxy = np.array([[50.0, 80.0, 10.0, 20.0]])
    detections = sv.Detections(xyxy=xyxy, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_inverted_bbox', 'get_detection_area', '3', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output

def test_get_detection_area_with_many_detections():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation performance with 100 detections.'
    num_detections = 100
    xyxy_list = []
    for i in range(num_detections):
        x1 = float(i * 10)
        y1 = float(i * 5)
        x2 = float(x1 + 100)
        y2 = float(y1 + 50)
        xyxy_list.append([x1, y1, x2, y2])
    xyxy = np.array(xyxy_list)
    detections = sv.Detections(xyxy=xyxy, class_id=np.arange(num_detections))
    areas = []
    for idx in [0, 50, 99]:
        codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_many_detections', 'get_detection_area', '7_0', codeflash_loop_index, detections, idx)
        codeflash_output = codeflash_return_value
        area = codeflash_output
        areas.append(area)
    for area in areas:
        pass

def test_get_detection_area_with_large_mask_image():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with a large mask image (1000x1000 pixels).'
    mask_size = 1000
    mask = np.zeros((mask_size, mask_size), dtype=np.uint8)
    center = (mask_size // 2, mask_size // 2)
    radius = 200
    cv.circle(mask, center, radius, 255, -1)
    mask_array = np.array([mask])
    xyxy = np.array([[0.0, 0.0, float(mask_size), float(mask_size)]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_large_mask_image', 'get_detection_area', '9', codeflash_loop_index, detections, 0)
    codeflash_output = codeflash_return_value
    area = codeflash_output
    expected_area = np.pi * radius ** 2

def test_get_detection_area_with_multiple_masks_in_batch():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation for multiple detections with masks.'
    num_detections = 50
    mask_list = []
    xyxy_list = []
    for i in range(num_detections):
        mask = np.zeros((200, 200), dtype=np.uint8)
        radius = 20 + i
        cv.circle(mask, (100, 100), radius, 255, -1)
        mask_list.append(mask)
        xyxy_list.append([0.0, 0.0, 200.0, 200.0])
    masks = np.array(mask_list)
    xyxy = np.array(xyxy_list)
    detections = sv.Detections(xyxy=xyxy, mask=masks, class_id=np.arange(num_detections))
    test_indices = [0, 25, 49]
    for idx in test_indices:
        codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_multiple_masks_in_batch', 'get_detection_area', '9_0', codeflash_loop_index, detections, idx)
        codeflash_output = codeflash_return_value
        area = codeflash_output
        expected_radius = 20 + idx
        expected_area = np.pi * expected_radius ** 2
        tolerance = expected_area * 0.1

def test_get_detection_area_consistency_across_iterations():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that area calculation is consistent when called multiple times.'
    mask = np.zeros((100, 100), dtype=np.uint8)
    cv.circle(mask, (50, 50), 30, 255, -1)
    mask_array = np.array([mask])
    xyxy = np.array([[10.0, 20.0, 50.0, 80.0]])
    detections = sv.Detections(xyxy=xyxy, mask=mask_array, class_id=np.array([0]))
    areas = []
    for _ in range(100):
        codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_consistency_across_iterations', 'get_detection_area', '7_0', codeflash_loop_index, detections, 0)
        codeflash_output = codeflash_return_value
        area = codeflash_output
        areas.append(area)
    first_area = areas[0]
    for area in areas[1:]:
        pass

def test_get_detection_area_with_densely_packed_detections():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test area calculation with 200 tightly packed detections.'
    num_detections = 200
    xyxy_list = []
    cols = 20
    for i in range(num_detections):
        row = i // cols
        col = i % cols
        x1 = float(col * 10)
        y1 = float(row * 10)
        x2 = float(x1 + 8)
        y2 = float(y1 + 8)
        xyxy_list.append([x1, y1, x2, y2])
    xyxy = np.array(xyxy_list)
    detections = sv.Detections(xyxy=xyxy, class_id=np.arange(num_detections))
    test_indices = [0, 100, 199]
    for idx in test_indices:
        codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_with_densely_packed_detections', 'get_detection_area', '8_0', codeflash_loop_index, detections, idx)
        codeflash_output = codeflash_return_value
        area = codeflash_output

def test_get_detection_area_return_type_is_always_float():
    np.random.seed(42)
    codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
    'Test that the return type is always float for various inputs.'
    xyxy_int = np.array([[10, 20, 50, 80]], dtype=np.int32)
    detections_int = sv.Detections(xyxy=xyxy_int.astype(np.float32), class_id=np.array([0]))
    xyxy_float = np.array([[10.5, 20.5, 50.5, 80.5]])
    detections_float = sv.Detections(xyxy=xyxy_float, class_id=np.array([0]))
    mask = np.zeros((100, 100), dtype=np.uint8)
    mask[25:75, 25:75] = 255
    mask_array = np.array([mask])
    detections_mask = sv.Detections(xyxy=xyxy_float, mask=mask_array, class_id=np.array([0]))
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_return_type_is_always_float', 'get_detection_area', '9', codeflash_loop_index, detections_int, 0)
    codeflash_output = codeflash_return_value
    area_int = codeflash_output
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_return_type_is_always_float', 'get_detection_area', '11', codeflash_loop_index, detections_float, 0)
    codeflash_output = codeflash_return_value
    area_float = codeflash_output
    codeflash_return_value = codeflash_wrap(get_detection_area, 'tests.inference.unit_tests.test_get_detection_area__unit_test_1', None, 'test_get_detection_area_return_type_is_always_float', 'get_detection_area', '13', codeflash_loop_index, detections_mask, 0)
    codeflash_output = codeflash_return_value
    area_mask = codeflash_output