from elasticsearch import NotFoundError
from corehq.apps.userreports.util import get_table_name
from corehq.apps.userreports.adapter import IndicatorAdapter
from corehq.apps.es.es_query import HQESQuery
from corehq.elastic import get_es_new
from dimagi.utils.decorators.memoized import memoized
from pillowtop.es_utils import INDEX_STANDARD_SETTINGS


def normalize_id(values):
    return '-'.join(values).replace(' ', '_')


class ESAlchemy(object):
    def __init__(self, index_name, config):
        self.index_name = index_name
        self.config = config
        self.es = HQESQuery(index_name)

    def __getitem__(self, sliced_or_int):
        hits = self.es[sliced_or_int]
        hits = [self._hit_to_row(hit) for hit in hits]
        if isinstance(sliced_or_int, (int, long)):
            return hits[0]
        return hits

    @property
    @memoized
    def column_ordering(self):
        columns = self.config.indicators.get_columns()
        return [col.database_column_name for col in columns]

    @property
    def column_descriptions(self):
        return [{"name": col} for col in self.column_ordering]

    def count(self):
        return self.es.count()


class IndicatorESAdapter(IndicatorAdapter):

    def __init__(self, config):
        super(IndicatorESAdapter, self).__init__(config)
        self.es = get_es_new()
        self.table_name = get_table_name(config.domain, config.table_id).lower()

    def rebuild_table(self):
        self.drop_table()
        self.es.indices.create(index=self.table_name, body=INDEX_STANDARD_SETTINGS)

    def drop_table(self):
        try:
            self.es.indices.delete(index=self.table_name)
        except NotFoundError:
            # index doesn't exist yet
            pass

    def rebuild_table_if_necessary(self):
        if not self.es.indices.exists(index=self.table_name):
            self.rebuild_table()

    def refresh_table(self):
        self.es.indices.refresh(index=self.table_name)

    def get_query_object(self):
        return ESAlchemy(self.table_name, self.config)

    def best_effort_save(self, doc):
        try:
            self.save(doc)
        except Exception as e:
            self.handle_exception(doc, e)

    def save(self, doc):
        """
        Saves the document. Should bubble up known errors.
        """
        indicator_rows = self.config.get_all_values(doc)
        if indicator_rows:
            es = get_es_new()
            for indicator_row in indicator_rows:
                primary_key_values = [i.value for i in indicator_row if i.column.is_primary_key]
                all_values = {i.column.database_column_name: i.value for i in indicator_row}
                es.index(
                    index=self.table_name, body=all_values,
                    id=normalize_id(primary_key_values), doc_type="indicator"
                )

@@ -1,12 +1,28 @@
+import datetime%0A
 from elastic
@@ -845,16 +845,804 @@
 n hits%0A%0A
+    @property%0A    @memoized%0A    def mapping(self):%0A        # todo: this should use the column configuration instead of mapping%0A        es = get_es_new()%0A        mapping = es.indices.get_mapping(index=self.index_name)%0A        return mapping%5Bself.index_name%5D%5B'mappings'%5D%5B'indicator'%5D%5B'properties'%5D%0A%0A    def _hit_to_row(self, hit):%0A        def mapping_to_datatype(col, value):%0A            type = self.mapping%5Bcol%5D%5B'type'%5D%0A            if type == 'date':%0A                try:%0A                    return datetime.datetime.strptime(value, %22%25Y-%25m-%25dT%25H:%25M:%25S%22)%0A                except ValueError:%0A                    return datetime.datetime.strptime(value, %22%25Y-%25m-%25dT%25H:%25M:%25S.%25f%22)%0A            return value%0A        return %7Bcol: mapping_to_datatype(col, hit%5Bcol%5D) for col in self.column_ordering%7D%0A%0A
     @pro

ESAlchemy should convert text dates to dates