# coding=utf-8
from __future__ import unicode_literals, absolute_import

import datetime

from dateutil.parser import parse
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from search.utils.es import es_index_adapt
from search.utils.es import get_es
from trans2es.type_info import get_type_info_map


class ConsistencyException(Exception):
    def __init__(self, key, row_value, document_value):
        message = "\n\nConsistency Error!\nError key:\t{key}\ndatabase value:\t{row_value}\nes value:\t{document_value}\n\n".format(
            key=key,
            row_value=row_value,
            document_value=document_value,
        )
        super(Exception, self).__init__(message)


class ConsistencyCheck(object):
    def __init__(self, type_info, pk_id):
        self.type_info = type_info
        self.pk_id = pk_id

    def check_consistency(self):
        def _check(key, row_value, document_value):
            if isinstance(row_value, datetime.datetime):
                document_value = parse(document_value)
            if row_value != document_value:
                raise ConsistencyException(key, row_value, document_value)

        row = self.get_row_data()
        document = self.get_es_data()
        for k, v in document.items():

            if isinstance(v, list):
                for index, k1 in enumerate(v):
                    if isinstance(k1, dict):
                        for k2, v2 in k1.items():
                            _check(k2, row[k][index][k2], v2)
                    else:
                        _check(k, row[k][index], k1)
            elif isinstance(v, dict):
                for k1, v1 in v.items():
                    _check(k, row[k][k1], v1)


            else:
                _check(k, row[k], v)

        print ('\n\n\nConsistency Check passed!\n\n\n')

    def get_row_data(self):
        instance = self.type_info.model.objects.get(pk=self.pk_id)
        row = self.type_info.get_data_func(instance)
        return row

    def get_es_data(self):
        f = [
            {'terms': {'_id': [self.pk_id]}}
        ]
        q = {
            'query': {
                'filtered':
                    {
                        'query': {'match_all': {}},
                        'filter': {'bool': {'must': f}}

                    },
            }
        }

        es = get_es()
        index = es_index_adapt(
            index_prefix=settings.ES_INDEX_PREFIX,
            doc_type=self.type_info.type,
            rw='read'
        )
        res = es.search(
            index=index,
            doc_type=self.type_info.type,
            timeout=settings.ES_SEARCH_TIMEOUT,
            body=q,
            from_=0,
            size=10)
        return res['hits']['hits'][0]['_source']


class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument(
            '--type',
            dest='type',
        )
        parser.add_argument(
            '--pk_id',
            dest='pk_id',
        )

    def check_command(self):
        for doc_type, type_info in get_type_info_map().items():
            instance = type_info.model.objects.order_by('id')[8]
            print(doc_type, instance.id)
            # from injection.data_sync.tasks import write_to_es
            # write_to_es(doc_type, [instance.id], None)
            check = ConsistencyCheck(
                type_info=type_info,
                pk_id=instance.id
            )
            check.check_consistency()

    def handle(self, *args, **options):
        if not options['type']:
            raise CommandError('type name must be specified')
        if not options['pk_id']:
            raise CommandError('type name must be specified')

        if options['type'] == 'problem':
            options['type'] = 'topic'

        type_info = get_type_info_map()[options['type']]

        check = ConsistencyCheck(
            type_info=type_info,
            pk_id=options['pk_id']
        )
        check.check_consistency()
