#!/usr/bin/env python3
"""
TTS 语音播报服务端 (ROS2 Service Server)
服务类型: origincar_msg/srv/Speak
主 TTS: Piper 离线模型  降级: espeak-ng
"""
import rclpy
import subprocess
import os
import wave

from rclpy.node import Node
from origincar_msg.srv import Speak

from piper import PiperVoice
from piper.config import SynthesisConfig

MODEL_PATH = '/home/sunrise/tts_model/zh_CN-huayan-medium.onnx'


class TTSServer(Node):
    def __init__(self):
        super().__init__('tts_server')

        self.declare_parameter('audio_sink',
                               'alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo')
        self.declare_parameter('tts_speed', 1.5)

        self.audio_sink = self.get_parameter('audio_sink').value
        tts_speed = self.get_parameter('tts_speed').value
        self.length_scale = 1.0 / tts_speed
        self.espeak_speed = int(175 * tts_speed)

        self.srv = self.create_service(Speak, '/tts/speak', self.handle_speak)

        self.get_logger().info(f'TTS Server ready | voice=zh_CN-huayan | speed={tts_speed}x | sink={self.audio_sink}')
        self.get_logger().info(f'Loading model: {MODEL_PATH}')
        self.voice = PiperVoice.load(MODEL_PATH)
        self.get_logger().info('Model loaded OK')

    def handle_speak(self, request, response):
        text = request.text.strip()
        if not text:
            response.success = False
            response.message = 'empty text'
            return response

        self.get_logger().info(f'TTS: {text}')

        try:
            syn_config = SynthesisConfig(length_scale=self.length_scale)
            wav_path = '/tmp/tts_out.wav'
            with wave.open(wav_path, 'wb') as wf:
                self.voice.synthesize_wav(text, wf, syn_config=syn_config)
            subprocess.Popen(
                ['paplay', f'--device={self.audio_sink}', wav_path],
                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            response.success = True
            response.message = 'ok'
        except Exception as e:
            self.get_logger().error(f'Piper TTS failed, fallback espeak: {e}')
            try:
                subprocess.Popen(
                    ['espeak-ng', '-v', 'cmn', '-s', str(self.espeak_speed), text],
                    env={**os.environ, 'PULSE_SINK': self.audio_sink},
                    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                response.success = True
                response.message = 'ok (espeak fallback)'
            except Exception as e2:
                self.get_logger().error(f'espeak also failed: {e2}')
                response.success = False
                response.message = str(e2)

        return response


def main(args=None):
    rclpy.init(args=args)
    node = TTSServer()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == '__main__':
    main()
