from datetime import datetime
from enum import Enum
import os
from typing import Dict, Union, List
import json

import attr

from staff.lib import requests


class JugglerStatus(Enum):
    OK = 'OK'
    CRIT = 'CRIT'
    WARN = 'WARN'


def juggler_status_serialize(_inst, _field, value):
    if isinstance(value, JugglerStatus):
        return value.value

    return value


@attr.s(auto_attribs=True)
class JugglerEvent:
    host: str
    service: str
    status: JugglerStatus
    description: str
    open_time: float
    tags: List[str]


@attr.s(auto_attribs=True)
class JugglerEvents:
    source: str
    events: List[JugglerEvent]


class Juggler:
    juggler_url = 'http://localhost:31579/events'

    def __init__(self, source: str):
        self._events_to_send: List[JugglerEvent] = []
        self._source = source
        self._host = os.getenv('DEPLOY_STAGE_ID')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, value, traceback):
        if not exc_type:
            self.flush()

    def add_event(self, service: str, status: JugglerStatus, description: str):
        ev = JugglerEvent(
            host=self._host,
            service=service,
            status=status,
            description=description,
            open_time=datetime.now().timestamp(),
        )
        self._events_to_send.append(ev)

    def add_ok_event(self, service: str):
        ev = JugglerEvent(
            host=self._host,
            service=service,
            status=JugglerStatus.OK,
            description='',
            open_time=datetime.now().timestamp(),
            tags=[],
        )
        self._events_to_send.append(ev)

    def add_crit_event(self, service: str, description: str, tags: List[str]):
        ev = JugglerEvent(
            host=self._host,
            service=service,
            status=JugglerStatus.CRIT,
            description=description,
            open_time=datetime.now().timestamp(),
            tags=tags,
        )
        self._events_to_send.append(ev)

    def flush(self):
        events = JugglerEvents(self._source, self._events_to_send)
        requests.post(self.juggler_url, json=attr.asdict(events, value_serializer=juggler_status_serialize))
        self._events_to_send = []

    def process_check_result(self, service: str, check_result: Union[Dict, List]):
        if check_result:
            tags = None
            if isinstance(check_result, dict) and 'tags' in check_result:
                tags = check_result.get('tags')
            if isinstance(check_result, list):
                check_result = {'problems': check_result}
            self.add_crit_event(service, json.dumps(check_result), tags or [])
        else:
            self.add_ok_event(service)
