#!/usr/bin/env python
"""Profile hot paths in NoteFlow audio processing.

Run with: python scripts/profile_hot_paths.py
Output: Profile statistics to stdout, sorted by cumulative time.
"""

from __future__ import annotations

import cProfile
import io
import pstats

import numpy as np
from numpy.typing import NDArray

from noteflow.config.constants import DEFAULT_SAMPLE_RATE
from noteflow.infrastructure.asr.segmenter import Segmenter, SegmenterConfig
from noteflow.infrastructure.asr.streaming_vad import StreamingVad
from noteflow.infrastructure.audio.levels import RmsLevelProvider

# Simulation parameters
SAMPLE_RATE = DEFAULT_SAMPLE_RATE
CHUNK_SIZE = 1600  # 100ms at 16kHz
SIMULATION_SECONDS = 60  # Simulate 1 minute of audio
CHUNKS_PER_SECOND = SAMPLE_RATE // CHUNK_SIZE


AudioChunk = NDArray[np.float32]


def generate_audio_stream(seconds: int) -> list[AudioChunk]:
    """Generate simulated audio chunks (alternating speech/silence)."""
    chunks: list[AudioChunk] = []
    total_chunks = seconds * CHUNKS_PER_SECOND

    for i in range(total_chunks):
        # Simulate speech/silence pattern (5s speech, 2s silence)
        if (i // CHUNKS_PER_SECOND) % 7 < 5:
            # Speech - higher amplitude
            chunk = np.random.randn(CHUNK_SIZE).astype(np.float32) * 0.3
        else:
            # Silence - low amplitude
            chunk = np.random.randn(CHUNK_SIZE).astype(np.float32) * 0.001
        chunks.append(chunk)

    return chunks


def process_stream(chunks: list[AudioChunk]) -> dict[str, int]:
    """Process audio stream through VAD + Segmenter pipeline."""
    vad = StreamingVad()
    segmenter = Segmenter(config=SegmenterConfig(sample_rate=SAMPLE_RATE))
    rms_provider = RmsLevelProvider()

    segments_emitted = 0
    speech_chunks = 0
    silence_chunks = 0

    for chunk in chunks:
        # VAD processing
        is_speech = vad.process_chunk(chunk)

        # RMS computation (for VU meter)
        _ = rms_provider.get_rms(chunk)
        _ = rms_provider.get_db(chunk)

        # Segmenter processing
        for _segment in segmenter.process_audio(chunk, is_speech):
            segments_emitted += 1

        if is_speech:
            speech_chunks += 1
        else:
            silence_chunks += 1

    # Flush remaining audio
    final_segment = segmenter.flush()
    if final_segment is not None:
        segments_emitted += 1

    return {
        "segments_emitted": segments_emitted,
        "speech_chunks": speech_chunks,
        "silence_chunks": silence_chunks,
    }


def main() -> None:
    """Run profiling and output statistics."""
    print(f"Generating {SIMULATION_SECONDS}s of simulated audio...")
    chunks = generate_audio_stream(SIMULATION_SECONDS)
    print(f"Generated {len(chunks)} chunks ({len(chunks) / CHUNKS_PER_SECOND:.1f}s)")

    print("\nProfiling audio processing pipeline...")
    profiler = cProfile.Profile()
    profiler.enable()

    result = process_stream(chunks)

    profiler.disable()

    print(f"\nResults: {result}")
    print("\n" + "=" * 80)
    print("PROFILE RESULTS (sorted by cumulative time)")
    print("=" * 80)

    # Output profile stats
    stream = io.StringIO()
    stats = pstats.Stats(profiler, stream=stream)
    stats.strip_dirs()
    stats.sort_stats(pstats.SortKey.CUMULATIVE)
    stats.print_stats(50)  # Top 50 functions

    print(stream.getvalue())

    # Also show by tottime
    print("\n" + "=" * 80)
    print("PROFILE RESULTS (sorted by total time in function)")
    print("=" * 80)

    stream2 = io.StringIO()
    stats2 = pstats.Stats(profiler, stream=stream2)
    stats2.strip_dirs()
    stats2.sort_stats(pstats.SortKey.TIME)
    stats2.print_stats(30)  # Top 30 functions

    print(stream2.getvalue())


if __name__ == "__main__":
    main()
