#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os, io, wave
from piper.voice import PiperVoice

# Path to the neural voice models
VOICE_DIR = "/usr/share/piper-voices"

# VOICE DATABASE (Required for importation in main.py)
# Metadata for supported voices: labels, filenames, sample rates, and base slow-down factors
VOICE_DATA = {
    "it_f": {"label": "Italiano (F)", "file": "it_IT-paola-medium.onnx", "rate": 22050, "slow": 1.25},
    "it_m": {"label": "Italiano (M)", "file": "it_IT-riccardo-x_low.onnx", "rate": 16000, "slow": 1.10},
    "de_f": {"label": "Deutsch (F)", "file": "de_DE-eva_k-x_low.onnx", "rate": 16000, "slow": 1.10},
    "de_m": {"label": "Deutsch (M)", "file": "de_DE-thorsten-medium.onnx", "rate": 22050, "slow": 1.20},
    "en_f": {"label": "English (F)", "file": "en_GB-alba-medium.onnx", "rate": 22050, "slow": 1.20},
    "en_m": {"label": "English (M)", "file": "en_GB-alan-medium.onnx", "rate": 22050, "slow": 1.20},
    "es_f": {"label": "Español (F)", "file": "es_MX-ald-medium.onnx", "rate": 22050, "slow": 1.05},
    "es_m": {"label": "Español (M)", "file": "es_ES-sharvard-medium.onnx", "rate": 22050, "slow": 1.15},
    "fr_f": {"label": "Français (F)", "file": "fr_FR-upmc-medium.onnx", "rate": 22050, "slow": 1.15},
    "fr_m": {"label": "Français (M)", "file": "fr_FR-tom-medium.onnx", "rate": 44100, "slow": 1.15},
}

class TTSEngine:
    """
    Core Text-to-Speech engine.
    Uses Piper to generate audio and calculates metadata for Karaoke synchronization.
    """
    def __init__(self):
        # Cache for loaded voice models to improve performance
        self.voices = {}

    def get_voice(self, model_file):
        """
        Loads and returns a Piper voice model. 
        If the model is already in cache, it returns the cached version.
        """
        if model_file not in self.voices:
            path = os.path.join(VOICE_DIR, model_file)
            if not os.path.exists(path):
                raise FileNotFoundError(f"Model file not found: {path}")
            self.voices[model_file] = PiperVoice.load(path)
        return self.voices[model_file]

    def generate_speech(self, text, v_info, speed_val):
        """
        Synthesizes text into audio data.
        Returns a tuple (wav_data, duration_ms).
        """
        try:
            voice = self.get_voice(v_info["file"])
            
            # Calculate the length_scale (speed) parameter
            # Piper logic: 1.0 is normal, > 1.0 is slower, < 1.0 is faster
            l_scale = (1.0 / speed_val) * v_info.get("slow", 1.0)
            
            # --- SPEED ADJUSTMENT TRICK ---
            # Attempt to set speed directly on the voice config object
            # This bypasses the 'unexpected keyword argument length_scale' error in some Piper versions
            try:
                if hasattr(voice, 'config'):
                    voice.config.length_scale = l_scale
                else:
                    voice.length_scale = l_scale
            except Exception as e:
                print(f"Warning: Could not set speed property: {e}")

            audio_raw = b''
            
            # Call synthesis without extra parameters to avoid crashes
            for chunk in voice.synthesize(text):
                # Handle output depending on what the specific Piper library version returns
                if hasattr(chunk, 'audio_int16_bytes'):
                    audio_raw += chunk.audio_int16_bytes
                elif hasattr(chunk, 'audio'):
                    audio_raw += chunk.audio
                else:
                    audio_raw += chunk

            if not audio_raw:
                return None, 0

            # Duration calculated on real bytes (crucial for Karaoke synchronization!)
            # Formula: (bytes / (sample_rate * 2 bytes per sample)) * 1000 ms
            durata_ms = (len(audio_raw) / (v_info["rate"] * 2)) * 1000
            
            # Create a WAV file buffer in memory
            buffer = io.BytesIO()
            with wave.open(buffer, "wb") as wav_file:
                wav_file.setnchannels(1)
                wav_file.setsampwidth(2)
                wav_file.setframerate(v_info["rate"])
                wav_file.writeframes(audio_raw)
            
            return buffer.getvalue(), durata_ms

        except Exception as e:
            print(f"Critical error in audio generation: {e}")
            import traceback
            traceback.print_exc()
            return None, 0
