from __future__ import annotations

import gc
import os
import time
from typing import Any, Callable, Optional

import pytest
from inference.core.workflows.core_steps.analytics.detection_event_log.v1 import (
    MAX_VIDEOS, DetectionEventLogBlockV1)

def codeflash_wrap(
    codeflash_wrapped: Callable[..., Any],
    codeflash_test_module_name: str,
    codeflash_test_class_name: Optional[str],
    codeflash_test_name: str,
    codeflash_function_name: str,
    codeflash_line_id: str,
    codeflash_loop_index: int,
    *args: Any,
    **kwargs: Any,
) -> str:
    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}"
    exception = None
    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}######$!")
    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

class TestEvictOldestVideoBasic:
    """Basic test cases for normal operating conditions."""

    def test_no_eviction_when_empty(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that eviction does nothing when there are no videos.'
        block = DetectionEventLogBlockV1()
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoBasic', 'test_no_eviction_when_empty', '_evict_oldest_video', '2', codeflash_loop_index)

    def test_no_eviction_when_at_max_videos(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that eviction does nothing when exactly at MAX_VIDEOS limit.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoBasic', 'test_no_eviction_when_at_max_videos', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_no_eviction_when_below_max_videos(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that eviction does nothing when below MAX_VIDEOS limit.'
        block = DetectionEventLogBlockV1()
        num_videos = MAX_VIDEOS - 10
        for i in range(num_videos):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoBasic', 'test_no_eviction_when_below_max_videos', '_evict_oldest_video', '4', codeflash_loop_index)

    def test_eviction_removes_oldest_video(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that eviction removes the video with the oldest access time.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {1: 'event_data'}
            block._last_flush_frame[video_id] = i * 10
            block._frame_count[video_id] = i * 5
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoBasic', 'test_eviction_removes_oldest_video', '_evict_oldest_video', '3', codeflash_loop_index)
        for i in range(1, MAX_VIDEOS + 1):
            video_id = f'video_{i}'

    def test_eviction_preserves_remaining_video_data(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that eviction preserves all data for remaining videos.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {i: f'event_{i}', i + 1: f'event_{i + 1}'}
            block._last_flush_frame[video_id] = i * 100
            block._frame_count[video_id] = i * 50
            block._last_access[video_id] = i
        expected_events = block._event_logs['video_1'].copy()
        expected_flush = block._last_flush_frame['video_1']
        expected_count = block._frame_count['video_1']
        expected_access = block._last_access['video_1']
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoBasic', 'test_eviction_preserves_remaining_video_data', '_evict_oldest_video', '7', codeflash_loop_index)

class TestEvictOldestVideoEdgeCases:
    """Edge case tests for unusual conditions."""

    def test_eviction_with_single_video_over_limit(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        "Test eviction when there's exactly one video over the limit."
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_single_video_over_limit', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_negative_access_times(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction handles negative access times correctly.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = -1000 + i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_negative_access_times', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_same_access_times(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction when multiple videos have the same access time.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = 0 if i < 2 else i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_same_access_times', '_evict_oldest_video', '3', codeflash_loop_index)
        removed_count = sum((1 for vid in ['video_0', 'video_1'] if vid not in block._event_logs))

    def test_eviction_with_reverse_access_pattern(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with newest videos having lowest access times.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = MAX_VIDEOS - i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_reverse_access_pattern', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_large_access_time_gaps(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with large gaps between access times.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = i * 1000000
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_large_access_time_gaps', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_complex_event_data(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction correctly removes complex nested event data.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {j: {'timestamp': j * 100, 'data': [1, 2, 3], 'nested': {'key': 'value'}} for j in range(10)}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_complex_event_data', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_missing_entries_in_some_dicts(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction when video exists in _last_access but missing from other dicts.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            if i == 0:
                block._last_access[video_id] = i
            else:
                block._event_logs[video_id] = {}
                block._last_flush_frame[video_id] = i
                block._frame_count[video_id] = i
                block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_missing_entries_in_some_dicts', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_zero_access_time(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction when oldest video has access time of zero.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = 0
            block._frame_count[video_id] = 0
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_with_zero_access_time', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_maintains_dictionary_consistency(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that all four dictionaries remain consistent after eviction.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoEdgeCases', 'test_eviction_maintains_dictionary_consistency', '_evict_oldest_video', '3', codeflash_loop_index)

class TestEvictOldestVideoLargeScale:
    """Large scale tests for performance and scalability."""

    def test_eviction_with_many_videos_over_limit(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction when significantly over MAX_VIDEOS limit.'
        block = DetectionEventLogBlockV1()
        num_videos = MAX_VIDEOS + 50
        for i in range(num_videos):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        for _ in range(50):
            initial_count = len(block._event_logs)
            if initial_count > MAX_VIDEOS:
                codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_with_many_videos_over_limit', '_evict_oldest_video', '4_1_0', codeflash_loop_index)

    def test_eviction_with_large_event_logs(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with videos containing many events.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {j: f'event_{j}' for j in range(500)}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_with_large_event_logs', '_evict_oldest_video', '3', codeflash_loop_index)
        for i in range(1, MAX_VIDEOS + 1):
            video_id = f'video_{i}'

    def test_eviction_performance_with_max_videos(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction performance at MAX_VIDEOS boundary.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {k: f'event_{k}' for k in range(100)}
            block._last_flush_frame[video_id] = i * 10
            block._frame_count[video_id] = i * 5
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_performance_with_max_videos', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_repeated_evictions_maintain_correctness(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test that repeated evictions always remove the oldest video.'
        block = DetectionEventLogBlockV1()
        num_videos = MAX_VIDEOS + 20
        for i in range(num_videos):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        removed_videos = []
        for expected_removed_idx in range(20):
            codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_repeated_evictions_maintain_correctness', '_evict_oldest_video', '5_0', codeflash_loop_index)
            removed_videos.append(f'video_{expected_removed_idx}')
        for video_id in removed_videos:
            pass

    def test_eviction_with_random_access_pattern(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with non-sequential access times.'
        block = DetectionEventLogBlockV1()
        access_times = [i * 37 % 1000 for i in range(MAX_VIDEOS + 1)]
        min_access_time = min(access_times)
        min_access_idx = access_times.index(min_access_time)
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = access_times[i]
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_with_random_access_pattern', '_evict_oldest_video', '6', codeflash_loop_index)

    def test_eviction_with_large_frame_counts(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with very large frame count values.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i * 1000000
            block._frame_count[video_id] = i * 1000000
            block._last_access[video_id] = i
        expected_flush = block._last_flush_frame['video_1']
        expected_count = block._frame_count['video_1']
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_with_large_frame_counts', '_evict_oldest_video', '5', codeflash_loop_index)

    def test_eviction_stress_test(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Stress test with maximum allowed data structures.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {j: {'data': f'event_{j}', 'value': j} for j in range(999)}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_stress_test', '_evict_oldest_video', '3', codeflash_loop_index)

    def test_eviction_with_string_video_ids_of_varying_length(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test eviction with video IDs of different string lengths.'
        block = DetectionEventLogBlockV1()
        for i in range(MAX_VIDEOS + 1):
            video_id = f"video_{'x' * (i % 50)}_{i}"
            block._event_logs[video_id] = {}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        oldest_video_id = f'video__{0}'
        codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_eviction_with_string_video_ids_of_varying_length', '_evict_oldest_video', '4', codeflash_loop_index)

    def test_multiple_evictions_in_sequence(self):
        codeflash_loop_index = int(os.environ['CODEFLASH_LOOP_INDEX'])
        'Test multiple sequential evictions maintain correct behavior.'
        block = DetectionEventLogBlockV1()
        num_videos = MAX_VIDEOS + 10
        for i in range(num_videos):
            video_id = f'video_{i}'
            block._event_logs[video_id] = {j: f'event_{j}' for j in range(50)}
            block._last_flush_frame[video_id] = i
            block._frame_count[video_id] = i
            block._last_access[video_id] = i
        for eviction_num in range(10):
            initial_count = len(block._event_logs)
            codeflash_return_value = codeflash_wrap(block._evict_oldest_video, 'tests.inference.unit_tests.test__evict_oldest_video__unit_test_1', 'TestEvictOldestVideoLargeScale', 'test_multiple_evictions_in_sequence', '_evict_oldest_video', '4_1', codeflash_loop_index)
        for i in range(10, num_videos):
            video_id = f'video_{i}'