import logging
import os
import json
from typing import Dict
import time

import google_measurement_protocol  # event, pageview, report

LOG = logging.getLogger("EventReporter")


class EventReporter(object):
    def __init__(self, conn, UA=None, queue_name=None):
        '''
        Initialize an EventReporter. Responsible for putting events
        and their timestamps into a simple Redis list queue.

        conn: Redis conn obj
        UA: GAMP property ID
        '''

        super(EventReporter, self).__init__()
        self.conn = conn
        default_ua = os.getenv('UA_ID')
        self.UA = UA or default_ua
        # default queue name (redis key) to store and fetch events
        default_queue_name = os.getenv('EVENTREPORTER_QUEUE_NAME', 'temp___eventreporterqueue')
        self.queue_name = queue_name or default_queue_name

        logging.basicConfig(level='WARNING', format='%(name)s | %(levelname)s | %(message)s')
        self.logger = logging.getLogger('EventReporter')
        self.logger.setLevel(logging.DEBUG)

    def get_ts(self):
        ''' current timestamp in ms '''
        return int(round(time.time() * 1000))

    def write_event(self, event):
        ''' write event to queue '''
        self.conn.rpush(self.queue_name, json.dumps(event))

    def fetch(self):
        ''' fetches a single event from the queue '''
        event = self.conn.rpop(self.queue_name)
        if event:
            return json.loads(event)
        else:
            return None

    def dispatch(self, data: Dict):
        '''
        Figures out the right handler to use for reporting and calls it
        with event data.

        Returns False if sending any request failed, otherwise True.
        '''
        if data['handler'] == 'ga':

            if not self.UA:
                raise ValueError('missing UA')

            # report offset between now and when we got the event (ms)
            data['args']['qt'] = str(self.get_ts() - data['ts'])

            if data['etype'] == 'event':
                payload = google_measurement_protocol.event(**data['args'])
            elif data['etype'] == 'pageview':
                payload = google_measurement_protocol.pageview(**data['args'])
            else:
                raise ValueError('unknown etype')

            # LOG.debug('payload: {}'.format(list(payload)))
            # send data (res is list of requests objs)
            res = google_measurement_protocol.report(self.UA, data['clientid'], payload)

            if not res:
                raise ValueError('nothing to send')

            for req in res:
               req.raise_for_status() 
            return True

        else:
            raise ValueError('unknown handler')

    def store(self, handler: str, etype: str, clientid: str, **data: Dict):
        '''
        Stores an event dict with its timestamp in ms onto a simple queue.

        Arguments:
            handler: 
                A string defining what handler the receiving worker should use.
            etype: 
                A string defining what event type the handler will see.
            clientid: 
                A string of valid UUID4 format for a unique clientid.

            the other args: 
                Any simple dict matching that handler's expectations.

        Called by e.g. API endpoints that need to return quickly.
        Returns value of queue op action.
        '''

        final_data = {
            "handler": handler,
            "etype": etype,
            "clientid": clientid,
            "ts": self.get_ts(),
            "args": data
        }

        # store event data
        r = self.write_event(final_data)

        debug_json = {"message": "new_eventreporter_report_json", **final_data}

        self.logger.debug(json.dumps(debug_json))

        return r
