from collections import deque
import logging
import nghttp2
import urllib
from urllib.parse import urlparse, parse_qs
import io
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import asyncio

LOG = logging.getLogger(__name__)
loop = asyncio.get_event_loop()

def _topic_translation(key, translation=str.maketrans('/', '.')):
    return key.translate(translation)


def create(config):
    return Controller(config)

class Serialiser(object):
    pass

class TextEventStream(Serialiser):
    @staticmethod
    def content_type():
        return 'text/event-stream'

    @staticmethod
    def serialise(message):
        body_in = io.BytesIO(message.payload)
        out = bytearray()
        for line in body_in:
            out.extend(b'data: ')
            out.extend(line)
            out.extend(b"\n")
        out.extend(b"\n")
        return out

class PlainTextStream(Serialiser):
    @staticmethod
    def content_type():
        return 'text/plain'

    @staticmethod
    def serialise(message):
        return b''.join([message.payload, b"\n"])


def create_serialiser(accept_string):
    media_ranges = { media_range: { key: value for key, value in map(lambda x: x.split('=', 1), param_list) } for media_range, *param_list in map(lambda x: map(lambda y: y.strip(), x.split(';')), accept_string.decode('ascii').split(',')) }

    for media_range, _ in sorted(media_ranges.items(), key=lambda x: float(x[1].get('q', 1.0)), reverse=True):
        # if fnmatch(TextEventStream.content_type(), media_range):
        return TextEventStream
        #elif fnmatch(PlainTextStream.content_type(), media_range):
        #    return PlainTextStream



class Controller(object):
    def __init__(self, config):
        self._config = config
        self._sessions = {}

    @property
    def config(self):
        return self._config

    def session(self, request):
        try:
            return self._sessions[request.session_id]
        except KeyError:
            session = Session(self.config, request)
            self._sessions[request.session_id] = session
            return session

    def post(self, request, start_response):
        return self.session(request).publish(request, start_response)

    def get(self, request, start_response):
        accept = next(i for i in request.headers if i[0] == b'accept')
        accept = accept[1] if not accept is None else b'text/event-stream'
        serialiser = create_serialiser(accept)

        start_response(200, [('content-type', serialiser.content_type()), ('cache-control', 'no-cache')])
        return self.session(request).subscribe(request, serialiser)


class Session(object):
    def __init__(self, config, request):
        self._config = config
        self._client = mqtt.Client(request.session_id, clean_session=False)
        self._client.on_connect = self._mqtt_on_connect
        self._client.on_log = self._mqtt_log
        self._client.username_pw_set(config.get('username', None), config.get('password', None))
        self._client.connect(config['host'], int(config.get('port', 1883)), int(config.get('keepalive', 5)))
        self._client.on_message = self._mqtt_message
        self._subscriptions = []
        self._stop = False
        asyncio.async(self.setup())

    @asyncio.coroutine
    def setup(self):
        LOG.debug("Connecting to %s", self._config)