import asyncio
import json
from typing import Any, Awaitable, Callable, Dict

from .. import app_config, util
from ..broker import Broker, BrokerOptions
from ..logger import Logger
from ..request import Request
from ..response import Response

NAME = 'WriteTranscript'
"""Name of the main class of the module.

Used by the App class
to obtain the correct class via getattr

"""


class WriteTranscript(Broker):
    """WriteTranscript broker class, inherits Broker."""

    def __init__(self, send_req_cb: Callable[[Request],
                                             Awaitable[None]]) -> None:
        """Constructor for WriteTranscript class.

        Args:
            send_req_cb (callable): callback that a broker can use to trigger
                sending another request. Set by the App class.

        Returns:
            None

        """
        self._logger = Logger(f'broker.{util.short_class_name(self)}')
        super().__init__(send_req_cb)

    async def start(self) -> None:
        """Starts the broker.

        Currently does nothing as there is no
        specific logic related to the broker startup. Reserved for
        future use and consistency with the parent class

        Args:
            None

        Returns
            None

        """
        pass

    async def process_request(self,
                              request: Request,
                              options: Dict[str, Any],
                              callback: Callable[[Request, Response],
                                                 Awaitable[None]]) -> None:
        """Processes the provided request and sends back responses.

        Uses the provided callback function

        Args:
            request (Request): Request message object
            options (Dict): broker options
            callback (Callable[[Request, Response], Awaitable[None]]):
                callback function to dispatch the responses to

        Returns
            None

        """
        response = Response()
        response.status = 'done'

        originator = request.originator

        # determine how to write back result
        follow_task: str = ''
        if originator['task'] == 'transcribe_voicemail':
            follow_task = 'write_voicemail_transcript'
        elif originator['task'] == 'transcribe_rtpengine_db_recording':
            follow_task = 'write_rtpengine_transcript'
        elif originator['task'] == 'transcribe_rtpengine_file_recording':
            follow_task = 'write_rtpengine_transcript'
            req_data = json.loads(originator['data'])
            originator['data'] = json.dumps({'db_id': req_data['db_id']})
        else:
            self.log.error('unknown originator for transcription task')

        # determine and transform format of result
        if isinstance(request.data, dict):
            # extract embedded response ( {'data': {'data': ... } } )
            if 'data' in request.data:
                request.data = request.data['data']

            # google long running operation:
            if 'metadata' in request.data \
                    and 'done' in request.data \
                    and 'response' in request.data \
                    and isinstance(request.data['response'], dict):
                request.data = request.data['response']

            # openai/lemonfox:
            if 'text' in request.data:
                response.data = request.data['text']
            # google:
            elif 'results' in request.data \
                    and isinstance(request.data['results'], list):
                text: str = ''
                for result in request.data['results']:
                    if not isinstance(result, dict):
                        continue
                    if 'transcript' in result:
                        text += result['transcript']
                    elif 'alternatives' in result \
                            and isinstance(result['alternatives'], list) \
                            and len(result['alternatives']) \
                            and 'transcript' in result['alternatives'][0]:
                        text += result['alternatives'][0]['transcript']
                response.data = text
            # google but without transcript:
            elif 'totalBilledTime' in request.data:
                response.data = '(no speech detected)'
            else:
                response.status = 'error'
                self.log.error(util.compact_str(
                    f'unknown reponse type: {str(request.data)}'
                ))
        else:
            response.status = 'error'
            self.log.error(util.compact_str(
                f'unknown reponse type: {str(request.data)}'
            ))

        await super().follow_tasks(request, response, options,
                                   {'task': follow_task})

        await asyncio.ensure_future(callback(request, response))
