#!/usr/bin/env python3
"""
Read-Aloud Service (Alt+R)
Monitors for Alt+R hotkey and reads highlighted text using Piper TTS (local neural voices)
"""

import os
import sys
import subprocess
import logging
import tempfile
from pathlib import Path
from pynput import keyboard

# Setup logging
logging.basicConfig(
    filename=os.path.expanduser("~/.cache/read_aloud.log"),
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# Configuration
LOCK_FILE = "/tmp/dictation_speaking.lock"
MIN_TEXT_LENGTH = 2  # Minimum characters to read

# Piper configuration
SCRIPT_DIR = Path(__file__).parent.parent.parent
PIPER_PATH = SCRIPT_DIR / ".venv" / "bin" / "piper"
VOICE_MODEL = Path.home() / ".shared" / "models" / "piper" / "en_US-lessac-medium.onnx"


class MiddleClickReader:
    """Monitors for Alt+R hotkey and reads selected text"""

    def __init__(self):
        self.is_reading = False
        self.last_text = ""
        self.alt_pressed = False
        logging.info("Read-aloud service initialized (use Alt+R)")

    def get_selected_text(self):
        """Get currently highlighted text from X11 PRIMARY selection"""
        try:
            result = subprocess.run(
                ["xclip", "-o", "-selection", "primary"],
                capture_output=True,
                text=True,
                timeout=1
            )
            if result.returncode == 0:
                return result.stdout.strip()
        except Exception as e:
            logging.error(f"Error getting selection: {e}")
        return ""

    def read_text(self, text):
        """Read text using Piper TTS (local neural voices)"""
        if not text or len(text) < MIN_TEXT_LENGTH:
            logging.debug(f"Text too short to read: '{text}'")
            return

        if self.is_reading:
            logging.debug("Already reading, skipping")
            return

        self.is_reading = True
        logging.info(f"Reading text: {text[:50]}...")

        try:
            # Create lock file to prevent feedback
            with open(LOCK_FILE, 'w') as f:
                f.write("read_aloud")

            # Create temporary WAV file for audio
            with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as tmp_file:
                audio_file = tmp_file.name

            try:
                # Generate speech with Piper
                piper_process = subprocess.Popen(
                    [
                        str(PIPER_PATH),
                        "--model", str(VOICE_MODEL),
                        "--output_file", audio_file
                    ],
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    text=True
                )

                # Send text to Piper via stdin
                piper_process.communicate(input=text, timeout=10)

                if piper_process.returncode == 0:
                    # Play audio with mpv (or aplay/paplay as fallback)
                    subprocess.run(
                        ["mpv", "--no-video", "--really-quiet", audio_file],
                        capture_output=True,
                        timeout=60
                    )
                    logging.info("Text read successfully")
                else:
                    logging.error(f"Piper TTS failed with code {piper_process.returncode}")

            finally:
                # Clean up temporary file
                if os.path.exists(audio_file):
                    os.remove(audio_file)

        except subprocess.TimeoutExpired:
            logging.error("TTS timed out")
        except Exception as e:
            logging.error(f"Error reading text: {e}")
        finally:
            # Remove lock file
            if os.path.exists(LOCK_FILE):
                try:
                    os.remove(LOCK_FILE)
                except Exception as e:
                    logging.error(f"Error removing lock file: {e}")
            self.is_reading = False

    def on_key_press(self, key):
        """Track Alt key and trigger on Alt+R"""
        try:
            # Track Alt key
            if key in [keyboard.Key.alt_l, keyboard.Key.alt_r, keyboard.Key.alt]:
                self.alt_pressed = True

            # Trigger on Alt+R
            if self.alt_pressed and hasattr(key, 'char') and key.char == 'r':
                logging.debug("Alt+R detected")

                # Get selected text
                text = self.get_selected_text()

                if text and text != self.last_text:
                    self.last_text = text
                    # Read in a separate thread to avoid blocking
                    import threading
                    read_thread = threading.Thread(
                        target=self.read_text,
                        args=(text,),
                        daemon=True
                    )
                    read_thread.start()
                elif not text:
                    logging.debug("No text selected")
        except Exception as e:
            logging.error(f"Error in key press handler: {e}")

    def on_key_release(self, key):
        """Track Alt key state"""
        try:
            if key in [keyboard.Key.alt_l, keyboard.Key.alt_r, keyboard.Key.alt]:
                self.alt_pressed = False
        except Exception as e:
            logging.error(f"Error in key release handler: {e}")

    def run(self):
        """Start the keyboard listener"""
        logging.info("Starting Alt+R listener...")
        print("Read-aloud service running. Press Alt+R on selected text to read it.")
        print("Press Ctrl+C to quit.")

        # Start keyboard listener
        with keyboard.Listener(
            on_press=self.on_key_press,
            on_release=self.on_key_release
        ) as listener:
            listener.join()


def main():
    try:
        reader = MiddleClickReader()
        reader.run()
    except KeyboardInterrupt:
        logging.info("Shutting down...")
        print("\nShutting down...")
    except Exception as e:
        logging.error(f"Fatal error: {e}")
        print(f"Error: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
