"""Negative test cases - verify that performance tests catch actual issues.

This module validates that our performance tests are effective by injecting
known problems and verifying they are detected.

Meta-testing: Test the tests!
"""

import gc
import logging
import threading
import time
from typing import Dict, List

import pytest

from mca_sdk import MCAClient
from mca_sdk.buffering.queue import TelemetryQueue

pytestmark = [pytest.mark.performance, pytest.mark.slow]

logger = logging.getLogger(__name__)


class LeakyObject:
    """Object that intentionally leaks memory."""

    _global_leak_list: List["LeakyObject"] = []

    def __init__(self, size_kb: int = 10):
        """Create leaky object with specified size.

        Args:
            size_kb: Size of leaked data in KB
        """
        # Create data that won't be garbage collected
        self.data = bytearray(size_kb * 1024)
        # Add to global list to prevent GC
        LeakyObject._global_leak_list.append(self)

    @classmethod
    def clear_leaks(cls):
        """Clear the leak list."""
        cls._global_leak_list.clear()


def test_negative_memory_leak_detection():
    """Verify memory leak test catches actual memory leaks.

    Injects intentional memory leak and validates detection.
    """
    import tracemalloc

    tracemalloc.start()

    # Baseline
    baseline_snapshot = tracemalloc.take_snapshot()
    baseline_memory = sum(stat.size for stat in baseline_snapshot.statistics("lineno"))

    # Inject memory leak
    leaked_objects = []
    leak_size_mb = 15  # Exceed 10MB threshold

    for i in range(100):
        # Leak 150KB per iteration = 15MB total
        leaked_objects.append(LeakyObject(size_kb=150))

        # Don't let GC clean these up
        if i % 10 == 0:
            gc.collect()

    # Measure after leak
    final_snapshot = tracemalloc.take_snapshot()
    final_memory = sum(stat.size for stat in final_snapshot.statistics("lineno"))

    growth_mb = (final_memory - baseline_memory) / 1024 / 1024

    tracemalloc.stop()

    logger.info("\nNegative Test - Memory Leak Detection:")
    logger.info(f"  Injected leak: {leak_size_mb} MB")
    logger.info(f"  Measured growth: {growth_mb:.2f} MB")

    # Verify leak was detected (growth should exceed 10MB threshold)
    assert growth_mb > 10, (
        f"Memory leak detection FAILED: Only detected {growth_mb:.2f}MB growth "
        f"when {leak_size_mb}MB was injected"
    )

    logger.info("  ✅ Memory leak successfully detected")

    # Cleanup
    LeakyObject.clear_leaks()
    leaked_objects.clear()
    gc.collect()


def test_negative_race_condition_detection():
    """Verify concurrency tests catch race conditions.

    Injects intentional race condition and validates detection.
    """
    # Shared counter without proper locking (intentional bug)
    unsafe_counter = {"value": 0}

    def unsafe_increment(count: int):
        """Increment counter without locking (race condition)."""
        for _ in range(count):
            # Read-modify-write without atomicity
            current = unsafe_counter["value"]
            time.sleep(0.00001)  # Increase chance of race
            unsafe_counter["value"] = current + 1

    # Run with multiple threads
    threads = []
    increments_per_thread = 1000
    num_threads = 10
    expected_total = increments_per_thread * num_threads

    for _ in range(num_threads):
        t = threading.Thread(target=unsafe_increment, args=(increments_per_thread,))
        threads.append(t)
        t.start()

    for t in threads:
        t.join()

    actual_value = unsafe_counter["value"]

    logger.info("\nNegative Test - Race Condition Detection:")
    logger.info(f"  Expected value: {expected_total}")
    logger.info(f"  Actual value: {actual_value}")
    logger.info(f"  Lost updates: {expected_total - actual_value}")

    # Verify race condition was detected (actual < expected)
    assert actual_value < expected_total, (
        f"Race condition detection FAILED: Got expected value {actual_value} "
        f"(should have lost updates due to race condition)"
    )

    logger.info("  ✅ Race condition successfully detected")


def test_negative_performance_degradation_detection():
    """Verify performance tests catch latency regressions.

    Injects artificial delay and validates detection.
    """
    from .performance_helpers import check_regression, load_performance_baselines

    # Load baseline
    baselines_data = load_performance_baselines()
    baseline_p95 = baselines_data.get("baselines", {}).get("latency_p95_ms", 0.02)

    # Simulate degraded performance (10x slower)
    degraded_p95 = baseline_p95 * 10

    # Check regression
    is_regression, message = check_regression(
        metric_name="latency_p95_ms",
        current_value=degraded_p95,
        baseline_value=baseline_p95,
        threshold_percent=20.0,
        higher_is_better=False,  # Lower latency is better
    )

    logger.info("\nNegative Test - Performance Degradation Detection:")
    logger.info(f"  Baseline p95: {baseline_p95}ms")
    logger.info(f"  Degraded p95: {degraded_p95}ms")
    logger.info(f"  {message}")

    # Verify regression was detected
    assert (
        is_regression
    ), "Performance degradation detection FAILED: 10x performance degradation not detected"

    logger.info("  ✅ Performance degradation successfully detected")


def test_negative_queue_overflow_detection():
    """Verify backpressure tests catch queue overflow issues.

    Injects queue overflow and validates detection.
    """
    max_size = 10
    queue = TelemetryQueue(max_size=max_size)

    # Fill queue beyond capacity
    items_pushed = 100
    for i in range(items_pushed):
        queue.enqueue({"item": i})

    # Verify queue enforced max_size
    final_size = queue.size()

    logger.info("\nNegative Test - Queue Overflow Detection:")
    logger.info(f"  Max size: {max_size}")
    logger.info(f"  Items pushed: {items_pushed}")
    logger.info(f"  Final size: {final_size}")
    logger.info(f"  Items dropped: {items_pushed - final_size}")

    # Verify overflow was detected and handled
    assert (
        final_size <= max_size
    ), f"Queue overflow detection FAILED: Queue size {final_size} exceeds max {max_size}"

    # Verify drops occurred
    expected_drops = items_pushed - max_size
    actual_drops = items_pushed - final_size

    assert (
        actual_drops >= expected_drops - 1
    ), (  # Allow off-by-one due to deque behavior
        f"Queue overflow detection FAILED: Expected ~{expected_drops} drops, got {actual_drops}"
    )

    logger.info("  ✅ Queue overflow successfully detected and handled")


def test_negative_cpu_instability_detection():
    """Verify CPU stability tests catch gradual CPU increase.

    Simulates CPU increase and validates detection.
    """
    from .performance_helpers import calculate_cpu_stability

    # Simulate CPU samples with gradual increase (5% growth)
    base_cpu = 10.0
    cpu_samples = []

    # First half: stable around base_cpu
    for i in range(50):
        cpu_samples.append(base_cpu + (i * 0.01))  # Slight natural variation

    # Second half: gradual increase (15% higher)
    increased_cpu = base_cpu * 1.15
    for i in range(50):
        cpu_samples.append(increased_cpu + (i * 0.01))

    # Check stability with 3% threshold
    is_stable, increase_percent = calculate_cpu_stability(cpu_samples, threshold_percent=3.0)

    logger.info("\nNegative Test - CPU Instability Detection:")
    logger.info(f"  First half average: {base_cpu:.2f}%")
    logger.info(f"  Second half average: {increased_cpu:.2f}%")
    logger.info(f"  Measured increase: {increase_percent:.1f}%")
    logger.info("  Threshold: 3.0%")
    logger.info(f"  Stable: {is_stable}")

    # Verify instability was detected (increase > 3%)
    assert not is_stable, (
        f"CPU instability detection FAILED: {increase_percent:.1f}% increase not detected "
        f"(threshold: 3.0%)"
    )

    logger.info("  ✅ CPU instability successfully detected")


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

    logger.info("=" * 60)
    logger.info("NEGATIVE TEST SUITE - Validating Test Effectiveness")
    logger.info("=" * 60)

    test_negative_memory_leak_detection()
    test_negative_race_condition_detection()
    test_negative_performance_degradation_detection()
    test_negative_queue_overflow_detection()
    test_negative_cpu_instability_detection()

    logger.info("\n" + "=" * 60)
    logger.info("ALL NEGATIVE TESTS PASSED - Test suite is effective!")
    logger.info("=" * 60)
