import asyncio
import argparse
import openai
import time

from .xunfei_speed_transcription.ost_fast import xf_transcriptor
from .openai_translation.chat import translate_sentence
from .audio.record import Detector
from .aws_streaming_transcription import live_stream
from .aws_streaming_transcription import prerecorded_stream


class gameTranslator:
    """
    An audio game translator class,

    This class provides functinalities for ...

    Attributes:
        filepath(str): file path for prerecorded audio file or to be recorded.
        transcription_model(str): choose from "aws_pre", "aws_live" and "xunfei".
        appid(str): xunfei transcription appid.
        apikey(str): xunfei transcription apikey.
        apisecret(str): xunfei transcription apisecret.
        pre_recorded(bool): whether needs prerecorded audio file.
        input_language(str): transcription input language.
        output_language(str): translation output language.
    """

    def __init__(
        self,
        transcription_model,
        filepath="",
        xunfei_appid="",
        xunfei_apikey="",
        xunfei_apisecret="",
        prerecorded=True,
        input_language="chinese",
        output_language="english",
    ):
        """
        Initialize a new instance of gameTranslator.

        Args:
            transcription_model(str): choose from "aws_pre", "aws_live" and "xunfei".
            filepath(str): file path for prerecorded audio file or to be recorded.
            xunfei_appid(str): xunfei transcription appid.
            xunfei_apikey(str): xunfei transcription apikey.
            xunfei_apisecret(str): xunfei transcription apisecret.
            prerecorded(bool): whether needs prerecorded audio file.
            input_language(str): transcription input language.
            output_language(str): translation output language.
            elapsed_time(float): duration once openai_translation is called to returned.
        """
        self.pre_recorded = prerecorded
        self.transcription_model = transcription_model
        self.appid = xunfei_appid
        self.apikey = xunfei_apikey
        self.apisecret = xunfei_apisecret
        self.filepath = filepath
        self.input_language = input_language.lower()
        self.output_language = output_language.lower()
        self.elapsed_time = 0

    def show_translator_info(self):
        """
        Show basic configurations of translator.

        Args:
            None
        Returns:
            None
        """
        print("****************************************")
        print("Transcription model : {}".format(self.transcription_model))
        if (
            self.transcription_model == "aws_pre"
            or self.transcription_model == "xunfei"
        ) and self.pre_recorded:
            print("Using prerecorded audio file : {}".format(self.filepath))
        else:
            print("Using prerecorded audio file : None")
        if (
            self.transcription_model == "aws_pre"
            or self.transcription_model == "xunfei"
        ) and not self.pre_recorded:
            print(
                "Temporery audio file generated by [aws_pre] saves at : {}".format(
                    self.filepath
                )
            )
        print("Input  language : {}".format(self.input_language))
        print("Output language : {}".format(self.output_language))
        print("****************************************")

    def show_time(self):
        """
        Show elapsed time for transcription and translation, including audio recording.

        Args:
            None
        Returns:
            None
        """
        print(f"Elapsed time: {self.elapsed_time:.3f} seconds")

    def record_audio(self):
        """
        Detects and records audio using pyaudio, saves at self.filepath.

        Args:
            None
        Returns:
            None
        """
        recorder = Detector(recording_file=self.filepath)
        recorder.detect_audio()

    def xunfei_transcription(self):
        """
        Transcripts audio file with xunfei speed transcription, if not self.pre_recorded, record() first.

        Args:
            None
        Returns:
            str: transcription result.
        """
        if not self.pre_recorded:
            self.record_audio()
        transcriptor = xf_transcriptor(
            self.appid, self.apikey, self.apisecret, self.filepath, self.input_language
        )
        transcriptor.get_fileurl()
        content = transcriptor.get_result()
        return content

    def aws_prerecored_transcription(self):
        """
        Transcripts audio file with awd_prerecorded transcription, if not self.pre_recorded, record() first.

        Args:
            None
        Returns:
            str: transcription result.
        """
        if not self.pre_recorded:
            self.record_audio()
        loop = asyncio.get_event_loop()
        result = loop.run_until_complete(
            prerecorded_stream.prerecorded_transcribe(
                self.filepath, self.input_language
            )
        )
        # loop.close()
        return result

    def aws_live_transcription(self):
        """
        Transcripts audio file with aws_live transcription. Record with pyaudio and send stream to aws simultaneously.

        Args:
            None
        Returns:
            str: transcription result.
        """
        loop = asyncio.get_event_loop()
        result = loop.run_until_complete(
            live_stream.live_transcribe(self.input_language)
        )
        # loop.close()
        return result

    def openai_translation(self):
        """
        Translates text to target language using openai.

        Args:
            None
        Returns:
            str: translation result.
        """
        start_time = time.time()
        self.show_translator_info()

        # first do transcription then translation
        if self.transcription_model == "xunfei":
            text = self.xunfei_transcription()
        elif self.transcription_model == "aws_pre":
            text = self.aws_prerecored_transcription()
        elif self.transcription_model == "aws_live":
            text = self.aws_live_transcription()

        res = translate_sentence(text, self.output_language)
        end_time = time.time()
        self.elapsed_time = end_time - start_time
        self.show_time()
        return res


def main():
    """
    main() function that takes cmd line input to instantiate and run a translator.
    """
    parser = argparse.ArgumentParser(description="audio based openai game translator")

    parser.add_argument("--openai_key", required=True, type=str, help="openai api key")

    modelparsers = parser.add_subparsers(
        dest="transcription_model",
        required=True,
        help="3 transcription models [xunfei], [aws_pre], [aws_live] to choose",
    )
    parser_xunfei = modelparsers.add_parser("xunfei")
    parser_xunfei.add_argument(
        "--xunfei_appid", type=str, required=True, help="xunfei appid"
    )
    parser_xunfei.add_argument(
        "--xunfei_apikey", type=str, required=True, help="xunfei apikey"
    )
    parser_xunfei.add_argument(
        "--xunfei_apisecret", type=str, required=True, help="xunfei api secret"
    )
    parser_xunfei.add_argument(
        "--file",
        dest="xunfei_file",
        type=str,
        required=True,
        default="./audio/test.wav",
        help="audio file path",
    )
    parser_xunfei.add_argument(
        "--pre_recorded",
        dest="pre_recorded_xunfei",
        action="store_true",
        help="if present, use prerecorded audio file in aws_pre",
    )

    parser_aws_pre = modelparsers.add_parser("aws_pre")
    parser_aws_pre.add_argument(
        "--file",
        dest="aws_file",
        type=str,
        required=True,
        default="./audio/test.wav",
        help="audio file path",
    )
    parser_aws_pre.add_argument(
        "--pre_recorded",
        dest="pre_recorded_aws",
        action="store_true",
        help="if present, use prerecorded audio file in aws_pre",
    )

    parser_aws_live = modelparsers.add_parser("aws_live")

    parser.add_argument(
        "-i",
        "--input_language",
        required=True,
        type=str,
        help="audio input language",
    )
    parser.add_argument(
        "-o",
        "--output_language",
        required=True,
        type=str,
        help="target translation language",
    )

    args = parser.parse_args()
    openai.api_key = args.openai_key

    new_translator = gameTranslator(
        args.transcription_model,
        filepath=args.xunfei_file
        if hasattr(args, "xunfei_file")
        else (args.aws_file if hasattr(args, "aws_file") else ""),
        xunfei_appid=args.xunfei_appid if hasattr(args, "xunfei_appid") else "",
        xunfei_apikey=args.xunfei_apikey if hasattr(args, "xunfei_apikey") else "",
        xunfei_apisecret=args.xunfei_apisecret
        if hasattr(args, "xunfei_apisecret")
        else "",
        prerecorded=args.pre_recorded_xunfei
        if hasattr(args, "pre_recorded_xunfei")
        else (args.pre_recorded_aws if hasattr(args, "pre_recorded_aws") else False),
        input_language=args.input_language,
        output_language=args.output_language,
    )
    new_translator.openai_translation()


if __name__ == "__main__":
    main()

# todo: precision
# todo: audio transmitting
# todo: add chat context [currently unavailable with openai api]
# [done]: add model description when initialize a model
# [done]: add argument constraint relationship
# [done]: duplicate in transcription output
# [done]: add timer
# [done]: sounddevice -> pyaudio, chunksize matters
# [done]: audio rms bar
