# coding=utf-8
from __future__ import absolute_import, unicode_literals, print_function
from django.core.management.base import BaseCommand, CommandError
from api.models import Service
from gm_types.gaia import SERVICE_ORDER_TYPE
from gm_types.doris import STRATEGY_TYPE
from search.utils.service import search_service
import random
import math
import datetime

from doris.models import ServiceStat
from api.models import Tag, Service
from search.utils.doris import get_params
from trans2es.utils.service_transfer import get_smart_rank


class Command(BaseCommand):
    RND_SERVICE_SIZE = 20
    SCORE_ORDER_TYPE = SERVICE_ORDER_TYPE.DORIS_SMART
    SCORE_ORDER_INDEX = 2  # 分数是排序的第几优先级
    DAY_OFFSET = 2
    GMEI_CREATED_DATE = datetime.date(2011, 8, 15)
    EPS = 1e-8

    @classmethod
    def feq(cls, a, b):
        return math.fabs(a-b)<cls.EPS

    def add_arguments(self, parser):
        parser.add_argument('--service-ids', type=int, nargs='*',
                            dest='service_ids')
        parser.add_argument('--query', type=str, dest='query')
        parser.add_argument('--user-city-tag-id', type=int, dest='user_city_tag_id')

    @classmethod
    def rnd_service_ids(cls, query):
        res = search_service(query=query,
                             size=cls.RND_SERVICE_SIZE,
                             sort_type=cls.SCORE_ORDER_TYPE,
                             sort_params={'user_city_tag_id':None})
        service_ids = []
        for s in res['hits']['hits']:
            service_ids.append(s['_source']['id'])

        return service_ids

    def get_es_scores(self, query, service_ids, user_city_tag_id):
        f = {
            'ids':service_ids
        }
        res = search_service(query=query,
                             size=len(service_ids),
                             sort_type=self.SCORE_ORDER_TYPE,
                             sort_params={'user_city_tag_id':user_city_tag_id},
                             filters=f)
        score_map = {service_id: None for service_id in service_ids}
        for d in res['hits']['hits']:
            service_id = d['_source']['id']
            score_map[service_id] = d['sort'][self.SCORE_ORDER_INDEX]

        return score_map

    def calc_scores(self, query, service_ids, user_city_tag_id):
        params = get_params(STRATEGY_TYPE.SERVICE_SEARCH)  # TODO: strategy name change
        today = datetime.date.today()
        stat_date_str = (today-datetime.timedelta(days=self.DAY_OFFSET)).strftime('%Y%m%d')

        def get_city_tag_id(service):
            if service.doctor and service.doctor.hospital and service.doctor.hospital.city:
                return service.doctor.hospital.city.tag_id
            elif service.hospital and service.hospital.city:
                return service.hospital.city.tag_id
            else:
                return None

        def calc_score(service):
            if Tag.objects.filter(name=query).count()==1:
                exact_tag_score = float(params['a'])
            else:
                exact_tag_score = 0.0

            try:
                stat = ServiceStat.objects.get(stat_date=stat_date_str,
                                               query=query,
                                               service_id=str(service_id),
                                               max_pv=0)
                stat_max = ServiceStat.objects.get(stat_date=stat_date_str,
                                                   query=query,
                                                   max_pv__gt=0)
                stat_score = float(params['b'])*math.log(stat.pv+1)/math.log(stat_max.max_pv+1)
            except ServiceStat.DoesNotExist:
                stat_score = 0.0

            if get_city_tag_id(service)==user_city_tag_id:
                tongcheng_score = float(params['c'])
            else:
                tongcheng_score = 0.0

            smart_rank_score = float(params['d'])*get_smart_rank(service)

            #assert service.start_time.date()>=self.GMEI_CREATED_DATE
            time_score = float(params['e'])*math.log(
                1+max(0, (service.start_time.date()-self.GMEI_CREATED_DATE).days)
            ) / math.log(
                1+(today-self.GMEI_CREATED_DATE).days
            )

            return exact_tag_score+stat_score+tongcheng_score+smart_rank_score+time_score

        score_map = {service_id: None for service_id in service_ids}
        for service_id in service_ids:
            service = Service.objects.get(pk=service_id)
            score_map[service_id] = calc_score(service)

        return score_map

    def handle(self, *args, **options):
        query = options['query'].decode('utf-8')
        user_city_tag_id = options['user_city_tag_id']
        if not options['service_ids']:
            service_ids = self.rnd_service_ids(query=query)
        else:
            service_ids = options['service_ids']

        es_scores = self.get_es_scores(query, service_ids, user_city_tag_id)
        calc_scores = self.calc_scores(query, service_ids, user_city_tag_id)
        for service_id in service_ids:
            if es_scores[service_id] is None:
                print('ES score for service_id[%d] is None' % service_id)
            elif calc_scores[service_id] is None:
                print('calculation score for service_id[%d] is None' % service_id)
            elif not self.feq(es_scores[service_id], calc_scores[service_id]):
                print('ES score[%f] and calculation score[%f] diff for service_id[%d]' % (
                    es_scores[service_id], calc_scores[service_id], service_id,))

