import sys
from dataclasses import fields

from speech_to_speech.arguments_classes.chat_tts_arguments import ChatTTSHandlerArguments
from speech_to_speech.arguments_classes.facebookmms_tts_arguments import FacebookMMSTTSHandlerArguments
from speech_to_speech.arguments_classes.faster_whisper_stt_arguments import FasterWhisperSTTHandlerArguments
from speech_to_speech.arguments_classes.kokoro_tts_arguments import KokoroTTSHandlerArguments
from speech_to_speech.arguments_classes.language_model_arguments import LanguageModelHandlerArguments
from speech_to_speech.arguments_classes.mlx_audio_whisper_arguments import MLXAudioWhisperSTTHandlerArguments
from speech_to_speech.arguments_classes.module_arguments import ModuleArguments
from speech_to_speech.arguments_classes.paraformer_stt_arguments import ParaformerSTTHandlerArguments
from speech_to_speech.arguments_classes.parakeet_tdt_arguments import ParakeetTDTSTTHandlerArguments
from speech_to_speech.arguments_classes.pocket_tts_arguments import PocketTTSHandlerArguments
from speech_to_speech.arguments_classes.qwen3_tts_arguments import Qwen3TTSHandlerArguments
from speech_to_speech.arguments_classes.responses_api_language_model_arguments import (
    ResponsesApiLanguageModelHandlerArguments,
)
from speech_to_speech.arguments_classes.socket_receiver_arguments import SocketReceiverArguments
from speech_to_speech.arguments_classes.socket_sender_arguments import SocketSenderArguments
from speech_to_speech.arguments_classes.vad_arguments import VADHandlerArguments
from speech_to_speech.arguments_classes.websocket_streamer_arguments import WebSocketStreamerArguments
from speech_to_speech.arguments_classes.whisper_stt_arguments import WhisperSTTHandlerArguments
from speech_to_speech.s2s_pipeline import ParsedArguments, parse_arguments


def test_release_defaults_match_responses_api_parakeet_qwen3_realtime_profile():
    module_args = ModuleArguments()
    vad_args = VADHandlerArguments()
    responses_api_args = ResponsesApiLanguageModelHandlerArguments()
    qwen3_args = Qwen3TTSHandlerArguments()

    assert module_args.mode == "realtime"
    assert module_args.stt == "parakeet-tdt"
    assert module_args.llm_backend == "responses-api"
    assert module_args.tts == "qwen3"
    assert module_args.log_level == "info"
    assert module_args.enable_live_transcription is True
    assert module_args.live_transcription_update_interval == 0.5

    assert vad_args.thresh == 0.6
    assert vad_args.min_silence_ms == 64
    assert vad_args.min_speech_ms == 384
    assert vad_args.min_speech_continuation_ms == 192
    assert vad_args.realtime_processing_pause == 0.5
    assert responses_api_args.model_name == "gpt-5.4-mini"
    assert responses_api_args.chat_size == 30
    assert responses_api_args.responses_api_stream is True
    assert qwen3_args.qwen3_tts_model_name == "Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice"
    assert qwen3_args.qwen3_tts_speaker == "Aiden"
    assert qwen3_args.qwen3_tts_language == "auto"
    assert qwen3_args.qwen3_tts_non_streaming_mode is True
    assert qwen3_args.qwen3_tts_ref_audio is None
    assert qwen3_args.qwen3_tts_mlx_quantization == "6bit"


# -- ParsedArguments dataclass tests ------------------------------------------

EXPECTED_FIELD_TYPES = {
    "module_kwargs": ModuleArguments,
    "socket_receiver_kwargs": SocketReceiverArguments,
    "socket_sender_kwargs": SocketSenderArguments,
    "websocket_streamer_kwargs": WebSocketStreamerArguments,
    "vad_handler_kwargs": VADHandlerArguments,
    "whisper_stt_handler_kwargs": WhisperSTTHandlerArguments,
    "paraformer_stt_handler_kwargs": ParaformerSTTHandlerArguments,
    "faster_whisper_stt_handler_kwargs": FasterWhisperSTTHandlerArguments,
    "mlx_audio_whisper_stt_handler_kwargs": MLXAudioWhisperSTTHandlerArguments,
    "parakeet_tdt_stt_handler_kwargs": ParakeetTDTSTTHandlerArguments,
    "language_model_handler_kwargs": LanguageModelHandlerArguments,
    "responses_api_language_model_handler_kwargs": ResponsesApiLanguageModelHandlerArguments,
    "chat_tts_handler_kwargs": ChatTTSHandlerArguments,
    "facebook_mms_tts_handler_kwargs": FacebookMMSTTSHandlerArguments,
    "pocket_tts_handler_kwargs": PocketTTSHandlerArguments,
    "kokoro_tts_handler_kwargs": KokoroTTSHandlerArguments,
    "qwen3_tts_handler_kwargs": Qwen3TTSHandlerArguments,
}


def test_parsed_arguments_has_all_expected_fields():
    actual_fields = {f.name: f.type for f in fields(ParsedArguments)}
    assert set(actual_fields) == set(EXPECTED_FIELD_TYPES)


def test_parsed_arguments_field_types_match():
    for f in fields(ParsedArguments):
        assert f.type is EXPECTED_FIELD_TYPES[f.name], (
            f"Field {f.name!r}: expected {EXPECTED_FIELD_TYPES[f.name].__name__}, got {f.type}"
        )


def test_parse_arguments_default_backend_returns_openai_api():
    original_argv = sys.argv[:]
    try:
        sys.argv = ["speech-to-speech"]
        args = parse_arguments()
    finally:
        sys.argv = original_argv

    assert isinstance(args, ParsedArguments)
    assert isinstance(args.module_kwargs, ModuleArguments)
    assert isinstance(args.responses_api_language_model_handler_kwargs, ResponsesApiLanguageModelHandlerArguments)
    assert isinstance(args.language_model_handler_kwargs, LanguageModelHandlerArguments)
    assert args.responses_api_language_model_handler_kwargs.model_name == "gpt-5.4-mini"
    assert args.module_kwargs.llm_backend == "responses-api"


def test_parse_arguments_transformers_backend():
    original_argv = sys.argv[:]
    try:
        sys.argv = ["speech-to-speech", "--llm_backend", "transformers"]
        args = parse_arguments()
    finally:
        sys.argv = original_argv

    assert isinstance(args, ParsedArguments)
    assert isinstance(args.language_model_handler_kwargs, LanguageModelHandlerArguments)
    assert isinstance(args.responses_api_language_model_handler_kwargs, ResponsesApiLanguageModelHandlerArguments)
    assert args.language_model_handler_kwargs.model_name == "Qwen/Qwen3-4B-Instruct-2507"
    # unused slot gets a default instance
    assert args.responses_api_language_model_handler_kwargs.model_name == "gpt-5.4-mini"


def test_parse_arguments_all_fields_populated():
    original_argv = sys.argv[:]
    try:
        sys.argv = ["speech-to-speech"]
        args = parse_arguments()
    finally:
        sys.argv = original_argv

    for f in fields(ParsedArguments):
        value = getattr(args, f.name)
        assert value is not None, f"Field {f.name!r} is None"
        assert isinstance(value, EXPECTED_FIELD_TYPES[f.name]), (
            f"Field {f.name!r}: expected {EXPECTED_FIELD_TYPES[f.name].__name__}, got {type(value).__name__}"
        )
