"""Lab 05 - Azure Speech in Foundry Tools, plus the full voice loop.

Objective 2.2 - Build a lightweight application by using Azure Speech;
                respond to spoken prompts by using a deployed multimodal model.

Run:  python 05_speech.py
"""
import os

from _common import banner, get_clients, require

banner("Lab 05 - Speech")

if not os.getenv("SPEECH_KEY"):
    print("  SPEECH_KEY not set. Create a Speech resource (or use your Foundry")
    print("  resource key) and set SPEECH_KEY + SPEECH_REGION in .env.\n")
    print("  Exam anchor: the Speech SDK always needs a KEY *and* a REGION.")
    print("  Speech resources are region-scoped; the wrong region is the")
    print("  single most common cause of a failed Speech call.")
    raise SystemExit(0)

import azure.cognitiveservices.speech as speechsdk

speech_config = speechsdk.SpeechConfig(
    subscription=require("SPEECH_KEY"),
    region=require("SPEECH_REGION"),
)
speech_config.speech_recognition_language = "en-GB"
speech_config.speech_synthesis_voice_name = "en-GB-SoniaNeural"

banner("Part A - Text to speech (plain)")

synth = speechsdk.SpeechSynthesizer(
    speech_config, speechsdk.audio.AudioOutputConfig(filename="out_plain.wav")
)
synth.speak_text_async("Your train departs from platform four in six minutes.").get()
print("  Wrote out_plain.wav")

banner("Part B - Text to speech with SSML")

# SSML is THE answer to any question about controlling how something is spoken.
ssml = """
<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis'
       xmlns:mstts='http://www.w3.org/2001/mstts' xml:lang='en-GB'>
  <voice name='en-GB-SoniaNeural'>
    <mstts:express-as style='newscast'>
      Your train departs from platform
      <emphasis level='strong'>four</emphasis>
      <break time='600ms'/>
      in <say-as interpret-as='cardinal'>6</say-as> minutes.
    </mstts:express-as>
    <break time='400ms'/>
    <prosody rate='-15%' pitch='+5%'>Please mind the gap.</prosody>
  </voice>
</speak>
"""
synth_ssml = speechsdk.SpeechSynthesizer(
    speech_config, speechsdk.audio.AudioOutputConfig(filename="out_ssml.wav")
)
synth_ssml.speak_ssml_async(ssml).get()
print("  Wrote out_ssml.wav - compare it with out_plain.wav")
print("""
  SSML elements worth memorising:
    <voice>              which neural voice
    <prosody>            rate, pitch, volume
    <break>              pauses
    <emphasis>           stress
    <say-as>             date / telephone / cardinal interpretation
    <phoneme>            exact pronunciation
    <mstts:express-as>   speaking style (cheerful, empathetic, newscast)
""")

banner("Part C - Speech to text from the microphone")

print("  Speak after the prompt (about 5 seconds of audio)...")
recognizer = speechsdk.SpeechRecognizer(
    speech_config, speechsdk.audio.AudioConfig(use_default_microphone=True)
)
result = recognizer.recognize_once_async().get()

transcript = ""
if result.reason == speechsdk.ResultReason.RecognizedSpeech:
    transcript = result.text
    print(f"  Recognised: {transcript}")
elif result.reason == speechsdk.ResultReason.NoMatch:
    print("  No speech recognised.")
else:
    details = result.cancellation_details
    print(f"  Cancelled: {details.reason} / {details.error_details}")

banner("Part D - Speech translation (one source, many targets)")

translation_config = speechsdk.translation.SpeechTranslationConfig(
    subscription=require("SPEECH_KEY"), region=require("SPEECH_REGION")
)
translation_config.speech_recognition_language = "en-GB"
for lang in ("fr", "de", "pt"):
    translation_config.add_target_language(lang)

print("  Speak again to translate...")
trans_result = speechsdk.translation.TranslationRecognizer(
    translation_config
).recognize_once_async().get()

if trans_result.reason == speechsdk.ResultReason.TranslatedSpeech:
    print(f"  source : {trans_result.text}")
    for lang, text in trans_result.translations.items():
        print(f"  {lang}     : {text}")

banner("Part E - The full voice loop: STT -> model -> TTS")

if transcript:
    _, openai = get_clients()
    reply = openai.responses.create(
        model=require("MODEL_DEPLOYMENT"),
        instructions="You are a rail assistant. Reply in one short sentence.",
        input=transcript,
    )
    print(f"  Model said: {reply.output_text}")

    speechsdk.SpeechSynthesizer(
        speech_config, speechsdk.audio.AudioOutputConfig(filename="out_reply.wav")
    ).speak_text_async(reply.output_text).get()
    print("  Wrote out_reply.wav")
else:
    print("  Skipped - no transcript captured.")

print("""
Exam anchors:
  - Speech SDK needs a KEY and a REGION
  - SSML controls pauses, emphasis, rate, pitch, pronunciation
  - Diarisation = who spoke when.  Speaker recognition = is it this person
  - Custom Neural Voice is LIMITED ACCESS (deepfake risk -> responsible AI)
  - Speech translation = speech.  Azure AI Translator = text
  - A multimodal model can collapse the middle of this loop, but it does NOT
    replace streaming transcription, diarisation, or custom voice
""")
