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

import aiofiles

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

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

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

"""


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

    def __init__(self, send_req_cb: Callable[[Request],
                                             Awaitable[None]]) -> None:
        """Constructor for File 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(util.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 = 'accepted'
        await asyncio.ensure_future(callback(request, response))

        response = Response()

        filename: str
        req_data = json.loads(request.data)
        filename = req_data['filename']

        try:
            async with aiofiles.open(filename, 'rb') as handle:
                response.data = await handle.read()
                await handle.close()
                response.data = bytes.decode(base64.b64encode(response.data))
                response.status = 'done'
        except OSError as err:
            response.status = 'error'
            if err.strerror:
                response.reason = err.strerror
            else:
                response.reason = 'unknown exception'

        await super().follow_tasks(request, response, options)

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