from datetime import datetime
from django.conf import settings
from libs.date import datetime_to_timestamp_millis
from libs.es import es_query, get_must_query, get_es
from libs.filters import area_tag_id_filter
from libs.debug import pretty_json
import traceback
import logging
import json
import time
from collections import Counter
from libs.error import logging_exception
from libs.cache import redis_client2


def get_hot_service_by_tags(tags, area_tag_id=None, offset=0, size=10):
    now = datetime.now()

    f = [
        {"term": {"is_online": True}},
        {"range": {"can_sold_time_range.start_time_long": {"lte": now}}},
        {"range": {"can_sold_time_range.end_time_long": {"gt": now}}},
    ]
    if area_tag_id:
        f.append(area_tag_id_filter(['doctor.hospital.', 'hospital.'], area_tag_id))

    f.append({
        "nested": {
            "path": "tag_heat",
            "query": {
                "bool": {
                    "must": {
                        "terms": {"tag_heat.tag_id": tags}
                    }
                }
            },
            "inner_hits": {}
        }
    })

    q = get_must_query(f)
    # 所有福利排序，下沉的与不可售的都需要放后面
    sorting = [
        {'_script': {
            'type': 'number',
            'order': 'asc',
            "script": {
                "id": "service-sink",
                "params": {"now": now}
            }
        }},
        {'_script': {
            'type': 'number',
            'order': 'desc',
            "script": {
                "id": "service-time-valid",
                "params": {"now": now}
            }
        }},
    ]
    sorting.append({
        "tag_heat.heat_score": {
            "order": "desc",
            "mode": "max",
            "nested_path": "tag_heat",
            "nested_filter": {
                "terms": {"tag_heat.tag_id": tags}
            }
        }
    })
    q["sort"] = sorting
    pretty_json(q)
    res = es_query('service', q, offset, size)

    hits = res['hits']['hits']
    hit_ids = [hit['_source']['id'] for hit in hits]
    return hit_ids


def get_point_service_by_diff_tags(point_hot_tags, user_service_portrait_tags,
                                   had_read_service_list, size, user_city_tag_id, in_whitelist):
    tags1 = list(set(user_service_portrait_tags).intersection(set(point_hot_tags)))
    tags2 = list(set(user_service_portrait_tags).difference(set(point_hot_tags)))
    tags3 = list(set(point_hot_tags).difference(set(user_service_portrait_tags)))
    try:
        q = dict()
        q["query"] = {"bool": {"must": [{"nested": {"path": "sku_list", "query": {
            "bool": {"must": [{"range": {"sku_list.price": {"le": 100000, "gte": 0}}}]}}}}, {
                                            "nested": {"path": "sku_list", "query": {"function_score": {"query": {
                                                "bool": {"must": [{"range": {"sku_list.start_time": {"lte": "now"}}},
                                                                  {"range": {"sku_list.end_time": {"gt": "now"}}}],
                                                         "should": [
                                                             {"range": {"sku_list.price": {"le": 100000, "gte": 0}}},
                                                             {"range": {"sku_list.start_time": {"lte": "now"}}},
                                                             {"range": {"sku_list.end_time": {"gt": "now"}}}],
                                                         "minimum_should_match": 1}}, "boost_mode": "replace",
                                                "score_mode": "max",
                                                "min_score": 0}},
                                                       "inner_hits": {"size": 1, "sort": [{"sku_list.price": "asc"},
                                                                                          "_score"]}}}]}}
        functions_list = []
        if len(tags1) > 0:
            functions_list.append({
                "filter": {
                    "bool": {
                        "must": {
                            "terms": {
                                "closure_tag_ids": tags1}
                        }
                    },
                },
                "weight": 100000
            }
            )

        if len(tags2) > 0:
            functions_list.append({
                "filter": {
                    "bool": {
                        "must": {
                            "terms": {
                                "closure_tag_ids": tags2}
                        }
                    },
                },
                "weight": 1000
            }
            )

        if len(tags3) > 0:
            functions_list.append({
                "filter": {
                    "bool": {
                        "must": {
                            "terms": {
                                "closure_tag_ids": tags3}
                        }
                    },
                },
                "weight": 100
            }
            )

        query_function_score = {
            "query": {
                "bool": {
                    "must": [
                        {
                            "term": {
                                "is_online": True
                            }
                        },
                        {"term": {"doctor.hospital.is_high_quality": True}},
                        {
                            "terms": {
                                "closure_tag_ids": tags1 + tags2 + tags3
                            }
                        }
                    ]
                }

            },
            "score_mode": "sum",
            "boost_mode": "sum",
            "functions": functions_list

        }
        q["query"] = {
            "function_score": query_function_score
        }

        if len(had_read_service_list) > 0:
            q["query"]["function_score"]["query"]["bool"]["must_not"] = {
                "terms": {
                    "id": had_read_service_list
                }
            }

        now = int(time.time())
        sort_rule = [  # 所有福利排序，下沉的与不可售的都需要放后面
            {'_script': {
                'type': 'number',
                'order': 'asc',
                "script": {
                    "id": "service-sink",
                    "params": {"now": now}
                }
            }},
            {'_script': {
                'type': 'number',
                'order': 'desc',
                "script": {
                    "id": "service-time-valid",
                    "params": {"now": now}
                }
            }},

        ]

        # 机构罚单下沉
        sort_rule += [
            {
                '_script': {
                    'type': 'number',
                    'order': 'asc',
                    "script": {
                        "id": "service-sink-by-org",
                        "params": {"now": now}
                    }
                }
            }
        ]
        sort_rule.append(
            {
                '_script': {
                    'type': 'number',
                    'order': 'desc',
                    "script": {
                        "id": "service-region-related",
                        "params": {
                            "user_city_tag_id": user_city_tag_id,
                            "in_whitelist": in_whitelist
                        }
                    }
                }
            }
        )
        sort_rule.append({"_score": {"order": "desc"}})
        sort_rule.append({
            "sku_list.price": {
                "order": "asc",
                "mode": "min",
                "nested_path": "sku_list",
                "nested_filter": {
                    "bool": {
                        "must": [
                            {
                                "range": {
                                    "sku_list.start_time": {"lte": "now"}
                                }
                            },
                            {
                                "range": {
                                    "sku_list.end_time": {"gt": "now"}
                                }
                            }
                        ]
                    }
                }
            }
        })
        sort_rule.append({'smart_rank2': {'order': 'desc'}})
        q['sort'] = sort_rule
        q['_source'] = {'includes': ['id']}

        res = es_query("service", q, 0, size)
        if res:
            service_ids = [i['_source']['id'] for i in res['hits']['hits']]
            if len(service_ids) == size:
                return service_ids
            else:
                return []
        else:
            return []
    except:
        logging.error("catch exception,err_msg:%s" % traceback.format_exc())
        logging_exception()
        return []


def get_user_service_portrait2_redis(cl_id, n=4):
    """
    :param cl_id: 设备id
    :param n: 获取画像的前n个tag
    :return: list
    """
    cl_id_portrait_key = "user:service_portrait_tags2:cl_id:" + str(cl_id)
    if redis_client2.exists(cl_id_portrait_key):
        user_portrait = redis_client2.hgetall(cl_id_portrait_key)
        user_portrait = {int(tag): float(score) for tag, score in user_portrait.items()}
        top_n = Counter(user_portrait).most_common(n)
        top_n_tags = [int(tag_info[0]) for tag_info in top_n]
    else:
        new_user_service_portrait_tags_key = "user:service_coldstart_tags2"
        user_portrait = redis_client2.hgetall(new_user_service_portrait_tags_key)
        user_portrait = {int(tag): float(score) for tag, score in user_portrait.items()}
        top_n = Counter(user_portrait).most_common(n)
        top_n_tags = [int(tag_info[0]) for tag_info in top_n]
    return top_n_tags


def get_user_history_order_tags(user_id, size=None):
    try:
        user_history_order_tags_key = "user:history_order:tags:user_id:" + str(user_id)
        if redis_client2.exists(user_history_order_tags_key):
            redis_user_history_order_tags = redis_client2.get(user_history_order_tags_key)
            if redis_user_history_order_tags:
                user_history_order_tags = json.loads(redis_user_history_order_tags)
            else:
                user_history_order_tags = []
            return user_history_order_tags[:size]
        else:
            return []
    except:
        logging.error("catch exception,err_msg:%s" % traceback.format_exc())
        logging_exception()
        return []
