"""Test performance comparison: Lock-based vs Lock-free TID counter."""

import threading
import time
import itertools


class OldTIDCounter:
    """OLD approach: Lock-based counter."""

    def __init__(self):
        self._tid_counter = 0
        self._send_lock = threading.Lock()

    def get_next_tid(self):
        with self._send_lock:
            self._tid_counter = (self._tid_counter + 1) % 256
            return self._tid_counter


class NewTIDCounter:
    """NEW approach: Lock-free counter using itertools.count."""

    def __init__(self):
        self._tid_counter = itertools.count(start=0, step=1)

    def get_next_tid(self):
        # GIL guarantees atomicity of next() on itertools.count
        return next(self._tid_counter) % 256


def benchmark_counter(counter, num_operations: int, num_threads: int = 1):
    """Benchmark counter with optional multi-threading."""

    def worker(operations_per_thread):
        for _ in range(operations_per_thread):
            counter.get_next_tid()

    operations_per_thread = num_operations // num_threads

    start = time.perf_counter()

    if num_threads == 1:
        worker(num_operations)
    else:
        threads = []
        for _ in range(num_threads):
            t = threading.Thread(target=worker, args=(operations_per_thread,))
            threads.append(t)
            t.start()

        for t in threads:
            t.join()

    elapsed = time.perf_counter() - start
    return elapsed


def main():
    print("=" * 70)
    print("TID Counter Performance Comparison: Lock-based vs Lock-free")
    print("=" * 70)

    num_operations = 100_000

    # Single-threaded test
    print(f"\n{'Test: SINGLE-THREADED':<40}")
    print(f"Operations: {num_operations:,}")
    print("-" * 70)

    old_counter = OldTIDCounter()
    old_time = benchmark_counter(old_counter, num_operations, num_threads=1)
    print(f"{'OLD (Lock-based)':<40} {old_time*1000:>8.2f} ms")

    new_counter = NewTIDCounter()
    new_time = benchmark_counter(new_counter, num_operations, num_threads=1)
    print(f"{'NEW (Lock-free itertools.count)':<40} {new_time*1000:>8.2f} ms")

    speedup = old_time / new_time
    print(f"\n{'Speedup:':<40} {speedup:.2f}x faster")
    print(
        f"{'Time per operation (OLD):':<40} {old_time/num_operations*1_000_000:.3f} µs"
    )
    print(
        f"{'Time per operation (NEW):':<40} {new_time/num_operations*1_000_000:.3f} µs"
    )

    # Multi-threaded test (simulating contention)
    print(f"\n{'='*70}")
    print(f"{'Test: MULTI-THREADED (4 threads)':<40}")
    print(f"Operations: {num_operations:,}")
    print("-" * 70)

    old_counter = OldTIDCounter()
    old_time_mt = benchmark_counter(old_counter, num_operations, num_threads=4)
    print(f"{'OLD (Lock-based with contention)':<40} {old_time_mt*1000:>8.2f} ms")

    new_counter = NewTIDCounter()
    new_time_mt = benchmark_counter(new_counter, num_operations, num_threads=4)
    print(f"{'NEW (Lock-free itertools.count)':<40} {new_time_mt*1000:>8.2f} ms")

    speedup_mt = old_time_mt / new_time_mt
    print(f"\n{'Speedup:':<40} {speedup_mt:.2f}x faster")
    print(f"{'Lock contention overhead:':<40} {(old_time_mt/old_time - 1)*100:.1f}%")

    # Real-world simulation
    print(f"\n{'='*70}")
    print("Real-world impact at 20Hz with 32 targets:")
    print("-" * 70)

    # JSON protocol: 1 TID per frame = 20 ops/sec
    json_ops_per_sec = 20
    json_overhead_old = (old_time / num_operations) * json_ops_per_sec * 1000
    json_overhead_new = (new_time / num_operations) * json_ops_per_sec * 1000

    print(f"JSON protocol (1 packet/frame @ 20Hz):")
    print(f"  OLD overhead: {json_overhead_old:.3f} ms/sec")
    print(f"  NEW overhead: {json_overhead_new:.3f} ms/sec")
    print(f"  Saved: {json_overhead_old - json_overhead_new:.3f} ms/sec")

    # Legacy protocol: 32 TID per frame = 640 ops/sec
    legacy_ops_per_sec = 32 * 20
    legacy_overhead_old = (old_time / num_operations) * legacy_ops_per_sec * 1000
    legacy_overhead_new = (new_time / num_operations) * legacy_ops_per_sec * 1000

    print(f"\nLegacy protocol (32 packets/frame @ 20Hz):")
    print(f"  OLD overhead: {legacy_overhead_old:.3f} ms/sec")
    print(f"  NEW overhead: {legacy_overhead_new:.3f} ms/sec")
    print(f"  Saved: {legacy_overhead_old - legacy_overhead_new:.3f} ms/sec")

    print(f"{'='*70}")


if __name__ == "__main__":
    main()
