import json
import socket
import threading

from django.conf import settings
from websocket import WebSocketException, create_connection

__all__ = ["EventPostingError", "EventPoster", "post", "last"]
_local = threading.local()


class EventPostingError(RuntimeError):
    pass


class EventPoster(object):
    def __init__(self):
        self._connect()

    def _connect(self):
        self._conn = create_connection(settings.EVENT_DAEMON_POST)
        if settings.EVENT_DAEMON_KEY is not None:
            self._conn.send(
                json.dumps({"command": "auth", "key": settings.EVENT_DAEMON_KEY})
            )
            resp = json.loads(self._conn.recv())
            if resp["status"] == "error":
                raise EventPostingError(resp["code"])

    def post(self, channel, message, tries=0):
        try:
            self._conn.send(
                json.dumps({"command": "post", "channel": channel, "message": message})
            )
            resp = json.loads(self._conn.recv())
            if resp["status"] == "error":
                raise EventPostingError(resp["code"])
            else:
                return resp["id"]
        except WebSocketException:
            if tries > 10:
                raise
            self._connect()
            return self.post(channel, message, tries + 1)

    def last(self, tries=0):
        try:
            self._conn.send('{"command": "last-msg"}')
            resp = json.loads(self._conn.recv())
            if resp["status"] == "error":
                raise EventPostingError(resp["code"])
            else:
                return resp["id"]
        except WebSocketException:
            if tries > 10:
                raise
            self._connect()
            return self.last(tries + 1)


def _get_poster():
    if "poster" not in _local.__dict__:
        _local.poster = EventPoster()
    return _local.poster


def post(channel, message):
    try:
        return _get_poster().post(channel, message)
    except (WebSocketException, socket.error):
        try:
            del _local.poster
        except AttributeError:
            pass
    return 0


def last():
    try:
        return _get_poster().last()
    except (WebSocketException, socket.error):
        try:
            del _local.poster
        except AttributeError:
            pass
    return 0