import logging
import datetime

import cassandra_helper as c_helper
import elasticsearch_helper as es_helper


logger = logging.getLogger('cessync')


def sync_collection(cass, es, db, collection, since):
    """
    Performs a state synchronization between a Cassandra columnfamily and an Elasticsearch type since a point in time.
    Reads on both stores are made in parallell. Writes are stiil blocking in this version.
    :param db: Cassandra keyspace and Elasticsearch index
    :param collection: Cassandra columnfamily and Elasticsearch type
    :param since: Date indicating the point in time from witch modifications should be synchronized
    """
    logger.info('Synchronization of collection {c} started at {t}'.format(c=collection, t=datetime.datetime.now()))

    future = c_helper.read_modified(cass, db, collection, since)
    es_records = es_helper.read_modified(es, db, collection, since)
    c_records = c_helper.fetch(future)

    to_cass = diff(c_records, es_records)
    to_es = diff(es_records, c_records)

    logger.info('Found {n} records to be inserted/updated in cassandra {c}'.format(n=len(to_cass), c=collection))
    logger.info('Found {n} records to be inserted/updated in elasticsearch {c}'.format(n=len(to_es), c=collection))

    c_helper.save_records(cass, db, collection, to_cass, False)
    es_helper.save_records(es, db, collection, to_es)

    logger.info('Synchronization of collection {c} completed at {t}'.format(c=collection, t=datetime.datetime.now()))


def diff(a, b):
    """
    Performs an inconsistency verification between two maps A and B of Records, and outputs a list of Records that
    should be inserted on A so that A state is consistent with B state.
    :param a: dict[uuid]: Record
    :param b: dict[uuid]: Record
    :return: list[Record]
    """
    result = []
    for key, val in b.iteritems():
        if key not in a:
            result.append(val)
        elif val.last_modified > a[key].last_modified:
            result.append(val)
    return result