#!/usr/bin/env python3
"""
Simple Oscillator Sensor Demo

This script demonstrates the oscillator sensor by:
1. Creating an oscillator sensor with various waveforms
2. Printing the waveform data in real-time

Usage:
    uv run python scripts/demo_oscillator_simple.py --waveform sine --frequency 1.0
    uv run python scripts/demo_oscillator_simple.py --waveform square --frequency 2.0
"""

import argparse
import math
import time
import sys
from pathlib import Path

# Add mainline to path
sys.path.insert(0, str(Path(__file__).parent.parent))

from engine.sensors.oscillator import OscillatorSensor, register_oscillator_sensor


def render_waveform(width: int, height: int, osc: OscillatorSensor, frame: int) -> str:
    """Render a waveform visualization."""
    # Get current reading
    current_reading = osc.read()
    current_value = current_reading.value if current_reading else 0.0

    # Generate waveform data - sample the waveform function directly
    # This shows what the waveform looks like, not the live reading
    samples = []
    waveform_fn = osc.WAVEFORMS[osc._waveform]

    for i in range(width):
        # Sample across one complete cycle (0 to 1)
        phase = i / width
        value = waveform_fn(phase)
        samples.append(value)

    # Build visualization
    lines = []

    # Header with sensor info
    header = (
        f"Oscillator: {osc.name} | Waveform: {osc.waveform} | Freq: {osc.frequency}Hz"
    )
    lines.append(header)
    lines.append("─" * width)

    # Waveform plot (scaled to fit height)
    num_rows = height - 3  # Header, separator, footer
    for row in range(num_rows):
        # Calculate the sample value that corresponds to this row
        # 0.0 is bottom, 1.0 is top
        row_value = 1.0 - (row / (num_rows - 1)) if num_rows > 1 else 0.5

        line_chars = []
        for x, sample in enumerate(samples):
            # Determine if this sample should be drawn in this row
            # Map sample (0.0-1.0) to row (0 to num_rows-1)
            # 0.0 -> row 0 (bottom), 1.0 -> row num_rows-1 (top)
            sample_row = int(sample * (num_rows - 1))
            if sample_row == row:
                # Use different characters for waveform vs current position marker
                # Check if this is the current reading position
                if abs(x / width - (osc._phase % 1.0)) < 0.02:
                    line_chars.append("◎")  # Current position marker
                else:
                    line_chars.append("█")
            else:
                line_chars.append(" ")
        lines.append("".join(line_chars))

    # Footer with current value and phase info
    footer = f"Value: {current_value:.3f} | Frame: {frame} | Phase: {osc._phase:.2f}"
    lines.append(footer)

    return "\n".join(lines)


def demo_oscillator(waveform: str = "sine", frequency: float = 1.0, frames: int = 0):
    """Run oscillator demo."""
    print(f"Starting oscillator demo: {waveform} wave at {frequency}Hz")
    if frames > 0:
        print(f"Running for {frames} frames")
    else:
        print("Press Ctrl+C to stop")
    print()

    # Create oscillator sensor
    register_oscillator_sensor(name="demo_osc", waveform=waveform, frequency=frequency)
    osc = OscillatorSensor(name="demo_osc", waveform=waveform, frequency=frequency)
    osc.start()

    # Run demo loop
    try:
        frame = 0
        while frames == 0 or frame < frames:
            # Render waveform
            visualization = render_waveform(80, 20, osc, frame)

            # Print with ANSI escape codes to clear screen and move cursor
            print("\033[H\033[J" + visualization)

            time.sleep(0.05)  # 20 FPS
            frame += 1

    except KeyboardInterrupt:
        print("\n\nDemo stopped by user")

    finally:
        osc.stop()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Oscillator sensor demo")
    parser.add_argument(
        "--waveform",
        choices=["sine", "square", "sawtooth", "triangle", "noise"],
        default="sine",
        help="Waveform type",
    )
    parser.add_argument(
        "--frequency", type=float, default=1.0, help="Oscillator frequency in Hz"
    )
    parser.add_argument(
        "--frames",
        type=int,
        default=0,
        help="Number of frames to render (0 = infinite until Ctrl+C)",
    )

    args = parser.parse_args()
    demo_oscillator(args.waveform, args.frequency, args.frames)
