# To use this code, make sure you
#
#     import json
#
# and then, to convert JSON from a string, do
#
#     result = bot_exchange_response_from_dict(json.loads(json_string))

from dataclasses import dataclass
from typing import Any, Optional, List, TypeVar, Callable, Type, cast


T = TypeVar("T")


def from_str(x: Any) -> str:
    assert isinstance(x, str)
    return x


def from_none(x: Any) -> Any:
    assert x is None
    return x


def from_union(fs, x):
    for f in fs:
        try:
            return f(x)
        except:
            pass
    assert False


def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
    assert isinstance(x, list)
    return [f(y) for y in x]


def to_class(c: Type[T], x: Any) -> dict:
    assert isinstance(x, c)
    return cast(Any, x).to_dict()


def from_int(x: Any) -> int:
    assert isinstance(x, int) and not isinstance(x, bool)
    return x


def from_bool(x: Any) -> bool:
    assert isinstance(x, bool)
    return x


@dataclass
class CustomPayload:
    pass

    @staticmethod
    def from_dict(obj: Any) -> 'CustomPayload':
        assert isinstance(obj, dict)
        return CustomPayload()

    def to_dict(self) -> dict:
        result: dict = {}
        return result


@dataclass
class Prompt:
    transcript: Optional[str] = None
    base64_encoded_g711_ulaw_with_wav_header: Optional[str] = None
    audio_file_path: Optional[str] = None
    text_to_speech: Optional[str] = None

    @staticmethod
    def from_dict(obj: Any) -> 'Prompt':
        assert isinstance(obj, dict)
        transcript = from_union([from_str, from_none], obj.get("transcript"))
        base64_encoded_g711_ulaw_with_wav_header = from_union([from_str, from_none], obj.get("base64EncodedG711ulawWithWavHeader"))
        audio_file_path = from_union([from_str, from_none], obj.get("audioFilePath"))
        text_to_speech = from_union([from_str, from_none], obj.get("textToSpeech"))
        return Prompt(transcript, base64_encoded_g711_ulaw_with_wav_header, audio_file_path, text_to_speech)

    def to_dict(self) -> dict:
        result: dict = {}
        result["transcript"] = from_union([from_str, from_none], self.transcript)
        result["base64EncodedG711ulawWithWavHeader"] = from_union([from_str, from_none], self.base64_encoded_g711_ulaw_with_wav_header)
        result["audioFilePath"] = from_union([from_str, from_none], self.audio_file_path)
        result["textToSpeech"] = from_union([from_str, from_none], self.text_to_speech)
        return result


@dataclass
class PromptSequence:
    prompts: Optional[List[Prompt]] = None

    @staticmethod
    def from_dict(obj: Any) -> 'PromptSequence':
        assert isinstance(obj, dict)
        prompts = from_union([lambda x: from_list(Prompt.from_dict, x), from_none], obj.get("prompts"))
        return PromptSequence(prompts)

    def to_dict(self) -> dict:
        result: dict = {}
        result["prompts"] = from_union([lambda x: from_list(lambda x: to_class(Prompt, x), x), from_none], self.prompts)
        return result


@dataclass
class ErrorDetails:
    error_behavior: Optional[int] = None
    error_prompt_sequence: Optional[PromptSequence] = None
    system_error_message: Optional[str] = None

    @staticmethod
    def from_dict(obj: Any) -> 'ErrorDetails':
        assert isinstance(obj, dict)
        error_behavior = from_union([from_int, from_none], obj.get("errorBehavior"))
        error_prompt_sequence = from_union([PromptSequence.from_dict, from_none], obj.get("errorPromptSequence"))
        system_error_message = from_union([from_str, from_none], obj.get("systemErrorMessage"))
        return ErrorDetails(error_behavior, error_prompt_sequence, system_error_message)

    def to_dict(self) -> dict:
        result: dict = {}
        result["errorBehavior"] = from_union([from_int, from_none], self.error_behavior)
        result["errorPromptSequence"] = from_union([lambda x: to_class(PromptSequence, x), from_none], self.error_prompt_sequence)
        result["systemErrorMessage"] = from_union([from_str, from_none], self.system_error_message)
        return result


@dataclass
class IntentInfo:
    intent: Optional[str] = None
    context: Optional[str] = None
    intent_confidence: Optional[int] = None
    last_user_utterance: Optional[str] = None
    slots: Optional[CustomPayload] = None

    @staticmethod
    def from_dict(obj: Any) -> 'IntentInfo':
        assert isinstance(obj, dict)
        intent = from_union([from_str, from_none], obj.get("intent"))
        context = from_union([from_str, from_none], obj.get("context"))
        intent_confidence = from_union([from_int, from_none], obj.get("intentConfidence"))
        last_user_utterance = from_union([from_str, from_none], obj.get("lastUserUtterance"))
        slots = from_union([CustomPayload.from_dict, from_none], obj.get("slots"))
        return IntentInfo(intent, context, intent_confidence, last_user_utterance, slots)

    def to_dict(self) -> dict:
        result: dict = {}
        result["intent"] = from_union([from_str, from_none], self.intent)
        result["context"] = from_union([from_str, from_none], self.context)
        result["intentConfidence"] = from_union([from_int, from_none], self.intent_confidence)
        result["lastUserUtterance"] = from_union([from_str, from_none], self.last_user_utterance)
        result["slots"] = from_union([lambda x: to_class(CustomPayload, x), from_none], self.slots)
        return result


@dataclass
class AudioTranscriptionConfig:
    transcription_profile_id: Optional[str] = None
    hint_phrases: Optional[List[str]] = None

    @staticmethod
    def from_dict(obj: Any) -> 'AudioTranscriptionConfig':
        assert isinstance(obj, dict)
        transcription_profile_id = from_union([from_str, from_none], obj.get("transcriptionProfileId"))
        hint_phrases = from_union([lambda x: from_list(from_str, x), from_none], obj.get("hintPhrases"))
        return AudioTranscriptionConfig(transcription_profile_id, hint_phrases)

    def to_dict(self) -> dict:
        result: dict = {}
        result["transcriptionProfileId"] = from_union([from_str, from_none], self.transcription_profile_id)
        result["hintPhrases"] = from_union([lambda x: from_list(from_str, x), from_none], self.hint_phrases)
        return result


@dataclass
class BargeConfiguration:
    enable_speaker_barge: Optional[bool] = None

    @staticmethod
    def from_dict(obj: Any) -> 'BargeConfiguration':
        assert isinstance(obj, dict)
        enable_speaker_barge = from_union([from_bool, from_none], obj.get("enableSpeakerBarge"))
        return BargeConfiguration(enable_speaker_barge)

    def to_dict(self) -> dict:
        result: dict = {}
        result["enableSpeakerBarge"] = from_union([from_bool, from_none], self.enable_speaker_barge)
        return result


@dataclass
class DtmfRules:
    detect_dtmf: Optional[bool] = None
    clear_digits: Optional[bool] = None
    termination_characters: Optional[str] = None
    strip_terminator: Optional[bool] = None
    inter_digit_timeout_milliseconds: Optional[int] = None
    max_digits: Optional[int] = None

    @staticmethod
    def from_dict(obj: Any) -> 'DtmfRules':
        assert isinstance(obj, dict)
        detect_dtmf = from_union([from_bool, from_none], obj.get("detectDtmf"))
        clear_digits = from_union([from_bool, from_none], obj.get("clearDigits"))
        termination_characters = from_union([from_str, from_none], obj.get("terminationCharacters"))
        strip_terminator = from_union([from_bool, from_none], obj.get("stripTerminator"))
        inter_digit_timeout_milliseconds = from_union([from_int, from_none], obj.get("interDigitTimeoutMilliseconds"))
        max_digits = from_union([from_int, from_none], obj.get("maxDigits"))
        return DtmfRules(detect_dtmf, clear_digits, termination_characters, strip_terminator, inter_digit_timeout_milliseconds, max_digits)

    def to_dict(self) -> dict:
        result: dict = {}
        result["detectDtmf"] = from_union([from_bool, from_none], self.detect_dtmf)
        result["clearDigits"] = from_union([from_bool, from_none], self.clear_digits)
        result["terminationCharacters"] = from_union([from_str, from_none], self.termination_characters)
        result["stripTerminator"] = from_union([from_bool, from_none], self.strip_terminator)
        result["interDigitTimeoutMilliseconds"] = from_union([from_int, from_none], self.inter_digit_timeout_milliseconds)
        result["maxDigits"] = from_union([from_int, from_none], self.max_digits)
        return result


@dataclass
class AudioCollectionRules:
    collection_type: Optional[int] = None
    dtmf_rules: Optional[DtmfRules] = None
    barge_configuration: Optional[BargeConfiguration] = None
    audio_transcription_config: Optional[AudioTranscriptionConfig] = None

    @staticmethod
    def from_dict(obj: Any) -> 'AudioCollectionRules':
        assert isinstance(obj, dict)
        collection_type = from_union([from_int, from_none], obj.get("collectionType"))
        dtmf_rules = from_union([DtmfRules.from_dict, from_none], obj.get("dtmfRules"))
        barge_configuration = from_union([BargeConfiguration.from_dict, from_none], obj.get("bargeConfiguration"))
        audio_transcription_config = from_union([AudioTranscriptionConfig.from_dict, from_none], obj.get("audioTranscriptionConfig"))
        return AudioCollectionRules(collection_type, dtmf_rules, barge_configuration, audio_transcription_config)

    def to_dict(self) -> dict:
        result: dict = {}
        result["collectionType"] = from_union([from_int, from_none], self.collection_type)
        result["dtmfRules"] = from_union([lambda x: to_class(DtmfRules, x), from_none], self.dtmf_rules)
        result["bargeConfiguration"] = from_union([lambda x: to_class(BargeConfiguration, x), from_none], self.barge_configuration)
        result["audioTranscriptionConfig"] = from_union([lambda x: to_class(AudioTranscriptionConfig, x), from_none], self.audio_transcription_config)
        return result


@dataclass
class SilenceRules:
    engage_comfort_sequence: Optional[bool] = None
    bot_response_delay_tolerance: Optional[int] = None
    comfort_prompt_sequence: Optional[PromptSequence] = None
    milliseconds_to_wait_for_user_response: Optional[int] = None

    @staticmethod
    def from_dict(obj: Any) -> 'SilenceRules':
        assert isinstance(obj, dict)
        engage_comfort_sequence = from_union([from_bool, from_none], obj.get("engageComfortSequence"))
        bot_response_delay_tolerance = from_union([from_int, from_none], obj.get("botResponseDelayTolerance"))
        comfort_prompt_sequence = from_union([PromptSequence.from_dict, from_none], obj.get("comfortPromptSequence"))
        milliseconds_to_wait_for_user_response = from_union([from_int, from_none], obj.get("millisecondsToWaitForUserResponse"))
        return SilenceRules(engage_comfort_sequence, bot_response_delay_tolerance, comfort_prompt_sequence, milliseconds_to_wait_for_user_response)

    def to_dict(self) -> dict:
        result: dict = {}
        result["engageComfortSequence"] = from_union([from_bool, from_none], self.engage_comfort_sequence)
        result["botResponseDelayTolerance"] = from_union([from_int, from_none], self.bot_response_delay_tolerance)
        result["comfortPromptSequence"] = from_union([lambda x: to_class(PromptSequence, x), from_none], self.comfort_prompt_sequence)
        result["millisecondsToWaitForUserResponse"] = from_union([from_int, from_none], self.milliseconds_to_wait_for_user_response)
        return result


@dataclass
class NextPromptBehaviors:
    silence_rules: Optional[SilenceRules] = None
    audio_collection_rules: Optional[AudioCollectionRules] = None

    @staticmethod
    def from_dict(obj: Any) -> 'NextPromptBehaviors':
        assert isinstance(obj, dict)
        silence_rules = from_union([SilenceRules.from_dict, from_none], obj.get("silenceRules"))
        audio_collection_rules = from_union([AudioCollectionRules.from_dict, from_none], obj.get("audioCollectionRules"))
        return NextPromptBehaviors(silence_rules, audio_collection_rules)

    def to_dict(self) -> dict:
        result: dict = {}
        result["silenceRules"] = from_union([lambda x: to_class(SilenceRules, x), from_none], self.silence_rules)
        result["audioCollectionRules"] = from_union([lambda x: to_class(AudioCollectionRules, x), from_none], self.audio_collection_rules)
        return result


@dataclass
class BotExchangeResponse:
    branch_name: Optional[int] = None
    next_prompt_sequence: Optional[PromptSequence] = None
    intent_info: Optional[IntentInfo] = None
    next_prompt_behaviors: Optional[NextPromptBehaviors] = None
    custom_payload: Optional[CustomPayload] = None
    error_details: Optional[ErrorDetails] = None

    @staticmethod
    def from_dict(obj: Any) -> 'BotExchangeResponse':
        assert isinstance(obj, dict)
        branch_name = from_union([from_int, from_none], obj.get("branchName"))
        next_prompt_sequence = from_union([PromptSequence.from_dict, from_none], obj.get("nextPromptSequence"))
        intent_info = from_union([IntentInfo.from_dict, from_none], obj.get("intentInfo"))
        next_prompt_behaviors = from_union([NextPromptBehaviors.from_dict, from_none], obj.get("nextPromptBehaviors"))
        custom_payload = from_union([CustomPayload.from_dict, from_none], obj.get("customPayload"))
        error_details = from_union([ErrorDetails.from_dict, from_none], obj.get("errorDetails"))
        return BotExchangeResponse(branch_name, next_prompt_sequence, intent_info, next_prompt_behaviors, custom_payload, error_details)

    def to_dict(self) -> dict:
        result: dict = {}
        result["branchName"] = from_union([from_int, from_none], self.branch_name)
        result["nextPromptSequence"] = from_union([lambda x: to_class(PromptSequence, x), from_none], self.next_prompt_sequence)
        result["intentInfo"] = from_union([lambda x: to_class(IntentInfo, x), from_none], self.intent_info)
        result["nextPromptBehaviors"] = from_union([lambda x: to_class(NextPromptBehaviors, x), from_none], self.next_prompt_behaviors)
        result["customPayload"] = from_union([lambda x: to_class(CustomPayload, x), from_none], self.custom_payload)
        result["errorDetails"] = from_union([lambda x: to_class(ErrorDetails, x), from_none], self.error_details)
        return result


def bot_exchange_response_from_dict(s: Any) -> BotExchangeResponse:
    return BotExchangeResponse.from_dict(s)


def bot_exchange_response_to_dict(x: BotExchangeResponse) -> Any:
    return to_class(BotExchangeResponse, x)
