from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import six

from functools import partial
import datetime
import pytz
import uuid

import requests

from ..core import ALL


class ArchiverEventSource(object):
    def __init__(self, url, timezone, pvs):
        """
        DataBroker plugin

        Parameters
        ----------
        url : string
            e.g., 'http://host:port/'
        timezone : string
            e.g., 'US/Eastern'
        pvs : dict
            a dict mapping human-friendly names to PVs
        """
        if not url.endswith('/'):
            url += '/'
        self.url = url
        self.archiver_addr = self.url + "retrieval/data/getData.json"
        self.tz = pytz.timezone(timezone)
        self.pvs = pvs
        self._descriptors = {}

    def insert(self, name, doc):
        raise NotImplementedError()

    def stream_names_given_header(self, header):
        # We actually don't use the header in this case.
        return ['archiver_{}'.format(name) for name in self.pvs]

    def fields_given_header(self, header):
        # We actually don't use the header in this case.
        return list(self.pvs)

    def descriptors_given_header(self, header):
        run_start_uid = header['start']['uid']
        try:
            return self._descriptors[run_start_uid]
        except KeyError:
            # Mock up descriptors and cache them so that the ephemeral uid is
            # stable for the duration of this process.
            descs = []
            start_time = header['start']['time'],
            stop_time = header['stop']['time']
            for name, pv in six.iteritems(self.pvs):
                data_keys = {name: {'source': pv,
                                    'dtype': 'number',
                                    'shape': []}}

                _from = _munge_time(start_time, self.tz)
                _to = _munge_time(stop_time, self.tz)
                params = {'pv': pv, 'from': _from, 'to': _to}
                desc = {'time': header['start']['time'],
                        'uid': 'empheral-' + str(uuid.uuid4()),
                        'data_keys': data_keys,
                        'run_start': header['start']['uid'],
                        'external_query': params,
                        'external_url': self.url}
                descs.append(desc)
            self._descriptors[run_start_uid] = descs
            prepare = partial(self.prepare_hook, 'descriptor')
            return list(map(prepare, self._descriptors[run_start_uid]))

    def docs_given_header(self, header, stream_name=ALL,
                          fill=False, fields=None,
                          **kwargs):
        desc_uids = {}
        for d in self.descriptors_given_header(header):
            # Stash the desc uids in a local var so we can use them in events.
            pv = list(d['data_keys'].values())[0]['source']
            desc_uids[pv] = d['uid']
            yield d
        start_time, stop_time = header['start']['time'], header['stop']['time']
        for name, pv in six.iteritems(self.pvs):
            _from = _munge_time(start_time, self.tz)
            _to = _munge_time(stop_time, self.tz)
            params = {'pv': pv, 'from': _from, 'to': _to}
            req = requests.get(self.archiver_addr, params=params, stream=True)
            req.raise_for_status()
            raw, = req.json()
            timestamps = [x['secs'] for x in raw['data']]
            data = [x['val'] for x in raw['data']]
            for seq_num, (d, t) in enumerate(zip(data, timestamps)):
                doc = {'data': {name: d},
                       'timestamps': {name: t},
                       'time': t,
                       'uid': 'ephemeral-' + str(uuid.uuid4()),
                       'seq_num': seq_num,
                       'descriptor': desc_uids[pv]}
                yield self.prepare_hook('event', doc)

    def table_given_header(self, header, timezone, fields=None):
        no_fields_filter = False
        if fields is None:
            no_fields_filter = True
            fields = []
        fields = set(fields)
        descs = self.descriptors_given_header(header)
        docs = list(self.docs_given_header(header=header,stream_name=ALL,
                                    fill=False, fields=fields))
        return pd.DataFrame.from_records(data=docs, index='seq_nums')

    def fill_event(self, *args, **kwrags):
        raise NotImplementedError()

    def fill_table(self, *args, **kwargs):
        raise NotImplementedError()


def _munge_time(t, timezone):
    """Close your eyes and trust @arkilic

    Parameters
    ----------
    t : float
        POSIX (seconds since 1970)
    timezone : pytz object
        e.g. ``pytz.timezone('US/Eastern')``

    Return
    ------
    time
        as ISO-8601 format
    """
    t = datetime.fromtimestamp(t)
    return timezone.localize(t).replace(microsecond=0).isoformat()

@@ -206,31 +206,8 @@
 ts%0A%0A
-from ..core import ALL%0A
 %0A%0Acl
@@ -2599,52 +2599,8 @@
 der,
- stream_name=ALL,%0A                          
 fill
@@ -3922,26 +3922,16 @@
  header,
- timezone,
  fields=
@@ -3933,24 +3933,61 @@
 elds=None):%0A
+        # TODO: Add timezone goodies%0A
         no_f
@@ -4238,24 +4238,8 @@
 der,
-stream_name=ALL,
 %0A   

Remove ALL that no longer exists