# -*- coding: UTF-8 -*-
import functools
import logging
import traceback
import copy
import json
import hashlib
from search.views.wiki_keyword import query_wiki_keyword
from libs.es import get_es, es_query, es_indices_analyze, get_highlight_query_analyzer, get_highlight_query
from extend.models.gaia import WordRel
from gm_rpcd.all import bind
from libs.algorithms import variousness
from libs.cache import redis_client
from django.db import models
from search.utils.diary import wordrel_some_list,get_wordrel_set


logger = logging.getLogger(__name__)

MAX_LOAD = 100
GROUP_SIZE = 10
variousness_per_10 = functools.partial(variousness, variety_size=GROUP_SIZE)


@bind('doris/search/query_wikitab')
def query_wiki(query='', offset=0, size=10, city_id='', source_type="tab", device_id=""):
    size = min(size, MAX_LOAD)

    try:
        assert (query is not None and len(query) > 0)
        es = get_es()
        body = {
            'text': query,
            'analyzer': "gm_default_index"
        }
        res = es_indices_analyze(doc_type="newwiki", body=body, es=es)

        wordrel_set,correct_term_list = get_wordrel_set(query)
        (total_query_term_list, complete_matching_term_list, other_key_word_term_list,other_key_word_term_str) = wordrel_some_list(res, wordrel_set, query)

        # 百科tab页
        if source_type == "tab":
            res = get_es_query_alpha(query, total_query_term_list,other_key_word_term_list, correct_term_list, offset, size)

            # if device_id in ["868771031984211"]:
            #     res = get_es_query_alpha(query, total_query_term_list, complete_matching_term_list,
            #                              synonym_term_list,
            #                              other_key_word_term_list, correct_term_list, offset, size)
            # else:
            #     res = get_es_query(query, total_query_term_list, complete_matching_term_list,
            #                        synonym_term_list,
            #                        other_key_word_term_list, correct_term_list, offset, size)

        # 综合页百科
        else:
            res = get_zonghe_query(query, correct_term_list)

        wiki_all = []
        wiki_extra = []

        if len(res["hits"]["hits"]) > 0:
            for item in res["hits"]["hits"]:
                id = item['_source']['id']
                wiki_type = item['_source']['wikitype']
                highlight = item.get("highlight", {})
                wiki_all.append([id, wiki_type])
                wiki_extra.append({"id": id, "wiki_type": wiki_type, "highlight": highlight})

            return {"wiki_all": wiki_all, 'is_valuable': True, "wiki_extra": wiki_extra}
        else:
            if source_type == "tab":
                wiki_keyword = query_wiki_keyword(city_id, offset=0, size=5, flag=True)

                for item in wiki_keyword:
                    wiki_all.append([item[1], item[2]])

                return {"wiki_all": wiki_all, 'is_valuable': False, "wiki_extra": []}
            else:
                return {"wiki_all": [], 'is_valuable': False, "wiki_extra": []}

    except:

        logging.error("catch exception, query_sku:%s" % traceback.format_exc())

        return {'wiki_all': [], 'is_valuable': bool(False), "wiki_extra": []}

def get_es_query_alpha(query, total_query_term_list,other_key_word_term_list, correct_term_list, offset, size):
    try:
        fields = ["name", "association_tags", "description", "use_result", "treatment_method", "effect", "ingredient",
                  "nature_type", "shape", "other_name", "other_name_pre", "tag_not_analyzed"]
        weight_fields = ["association_tags", "tag_not_analyzed"]

        total_query_term_str = " ".join(total_query_term_list)
        query_list = correct_term_list + other_key_word_term_list
        q = {
            "query": {
                "function_score": {
                    "query": {
                        "bool": {
                            "minimum_should_match": 1,
                            "should": [
                                {
                                    "multi_match": {
                                        "query": total_query_term_str,
                                        "fields": fields,
                                        "analyzer": "whitespace"
                                    }
                                }, {
                                    "nested": {
                                        "path": "related_drug",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "multi_match": {
                                                        "query": query,
                                                        "fields": ["related_drug.name"],
                                                        "analyzer": "gm_default_index",
                                                        "operator": "and",
                                                        "type": "best_fields"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }, {
                                    "nested": {
                                        "path": "related_instrument",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "multi_match": {
                                                        "query": query,
                                                        "fields": ["related_instrument.name"],
                                                        "analyzer": "gm_default_index",
                                                        "operator": "and",
                                                        "type": "best_fields"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }, {
                                    "nested": {
                                        "path": "related_material",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "multi_match": {
                                                        "query": query,
                                                        "fields": ["related_material.name"],
                                                        "analyzer": "gm_default_index",
                                                        "operator": "and",
                                                        "type": "best_fields"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }, {
                                    "nested": {
                                        "path": "related_brand",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "multi_match": {
                                                        "query": query,
                                                        "fields": ["related_brand.name"],
                                                        "analyzer": "gm_default_index",
                                                        "operator": "and",
                                                        "type": "best_fields"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            ],
                            "must": {
                                "term": {
                                    "is_online": True
                                }
                            },
                            "must_not": {
                                "term": {
                                    "description": "none"
                                }
                            }
                        }
                    },
                    "score_mode": "sum",
                    "boost_mode": "replace",
                    "functions": [
                        {
                            "filter": {
                                "term": {
                                    "name_pre": query
                                }
                            },
                            "weight": 10000
                        },
                        {
                            "filter": {
                                "terms": {
                                    "name_pre": correct_term_list
                                }
                            },
                            "weight": 8000
                        },
                        {
                            "filter": {
                                "terms": {
                                    "name": correct_term_list
                                }
                            },
                            "weight": 5000
                        },
                        {
                            "filter": {
                                "terms": {
                                    "other_name_pre": correct_term_list
                                }
                            },
                            "weight": 7000
                        }
                    ]
                }
            }
        }

        fields = ["name", "association_tags", "other_name", "other_name_pre", "tag_not_analyzed"]

        for field_item in fields:
            for query_item in total_query_term_list:
                term_dict = {
                    "filter":{
                        "term":{
                            field_item: query_item
                        }
                    },
                    "weight":100
                }
                q["query"]["function_score"]["functions"].append(term_dict)


        weight_fields_correct_term_list = list()
        for field_name in weight_fields:
            term_dict = {
                "terms": {
                    field_name: correct_term_list
                }
            }
            weight_fields_correct_term_list.append(term_dict)
        function_score_item = {
            "weight": 500,
            "filter": {
                "bool": {
                    "minimum_should_match": 1,
                    "should": weight_fields_correct_term_list
                }
            }
        }
        q["query"]["function_score"]["functions"].append(function_score_item)

        q['highlight'] = get_highlight_query_analyzer(["name", "description"], query)

        logging.info("get get_es_query_alpha:%s" % q)

        res = es_query('newwiki', q, offset, size)

        return res
    except:
        logging.error("catch exception, query_sku:%s" % traceback.format_exc())
        return []


def get_es_query(query, total_query_term_list, complete_matching_term_list,
                 synonym_term_list,
                 other_key_word_term_list, correct_term_list, offset, size):
    try:

        multi_fields = {
            'name': 1,
            'association_tags': 1,
            "description": 1,
            "use_result": 1,
            "treatment_method": 1,
            "effect": 1,
            "ingredient": 1,
            "nature_type": 1,
            "shape": 1,
            "other_name": 1,
            "tag_not_analyzed": 1
        }

        fields = ['^'.join((k, str(v))) for (k, v) in multi_fields.items()]

        querys = " ".join(correct_term_list)

        multi_match = {
            'query': querys,
            'type': 'cross_fields',
            'operator': 'and',
            'fields': fields,
        }

        q = {"query": {
            "function_score": {
                "query": {
                    "bool": {
                        "disable_coord": True,
                        "minimum_should_match": 1,
                        "should": [{
                            "multi_match": multi_match
                        }, {
                            "nested": {
                                "path": "related_drug",
                                "query": {
                                    "bool": {
                                        "must": {
                                            "match": {
                                                "related_drug.name": querys
                                            }
                                        }
                                    }
                                }
                            }
                        }, {
                            "nested": {
                                "path": "related_instrument",
                                "query": {
                                    "bool": {
                                        "must": {
                                            "match": {
                                                "related_instrument.name": querys
                                            }
                                        }
                                    }
                                }
                            }
                        }, {
                            "nested": {
                                "path": "related_material",
                                "query": {
                                    "bool": {
                                        "must": {
                                            "match": {
                                                "related_material.name": querys
                                            }
                                        }
                                    }
                                }
                            }
                        }, {
                            "nested": {
                                "path": "related_brand",
                                "query": {
                                    "bool": {
                                        "must": {
                                            "match": {
                                                "related_brand.name": querys
                                            }
                                        }
                                    }
                                }
                            }
                        }],
                        "must": {
                            "term": {
                                "is_online": True
                            }
                        },
                        "must_not": {
                            "term": {
                                "description": "none"
                            }
                        }

                    }
                },
                "score_mode": "sum",
                "boost_mode": "sum",
                "functions": [
                    {
                        "filter": {
                            "term": {
                                "name_pre": query
                            }
                        },
                        "weight": 10000
                    },
                    {
                        "filter": {
                            "term": {
                                "name": query
                            }
                        },
                        "weight": 100
                    },
                    {
                        "filter": {
                            "term": {
                                "other_name_pre": query
                            }
                        },
                        "weight": 100
                    },
                    {"filter": {
                        "bool": {
                            "should": [{
                                "multi_match": multi_match
                            },
                                {
                                    "nested": {
                                        "path": "related_drug",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "match": {
                                                        "related_drug.name": " ".join(total_query_term_list)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                },
                                {
                                    "nested": {
                                        "path": "related_instrument",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "match": {
                                                        "related_instrument.name": " ".join(total_query_term_list)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                },
                                {
                                    "nested": {
                                        "path": "related_material",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "match": {
                                                        "related_material.name": " ".join(total_query_term_list)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                },
                                {
                                    "nested": {
                                        "path": "related_brand",
                                        "query": {
                                            "bool": {
                                                "must": {
                                                    "match": {
                                                        "related_brand.name": " ".join(total_query_term_list)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            ]
                        }
                    },
                        "weight": 1

                    }
                ],
            }
        }
        }

        if len(total_query_term_list) > 0:
            q["query"]["function_score"]["query"] = {
                "constant_score": {
                    "filter": {
                        "multi_match": {
                            "query": " ".join(total_query_term_list),
                            "fields": fields,
                            "analyzer": "whitespace"
                        }
                    }
                }
            }

            if len(complete_matching_term_list) > 0:
                for complete_matching_term in complete_matching_term_list:
                    q["query"]["function_score"]["functions"].append(
                        {
                            "filter": {
                                "multi_match": {
                                    "query": complete_matching_term,
                                    "fields": fields,
                                    "analyzer": "gm_default_index"
                                }
                            },
                            "weight": 300

                        }

                    )
            if len(synonym_term_list) > 0:
                q["query"]["function_score"]["functions"].append(
                    {
                        "filter": {
                            "terms": {
                                "name_pre": synonym_term_list,
                            }
                        },
                        "weight": 300

                    }

                )
            if len(synonym_term_list) > 0:
                for synonym_term in synonym_term_list:
                    q["query"]["function_score"]["functions"].append(
                        {
                            "filter": {
                                "multi_match": {
                                    "query": synonym_term,
                                    "fields": fields,
                                    "analyzer": "whitespace"

                                }
                            },
                            "weight": 250
                        }
                    )
            if len(other_key_word_term_list) > 0:
                for other_key_word_term in other_key_word_term_list:
                    q["query"]["function_score"]["functions"].append(
                        {"filter":
                            {"multi_match": {
                                "query": other_key_word_term,
                                "fields": fields,
                                "analyzer": "whitespace"

                            }
                            },
                            "weight": 200
                        }
                    )
        q['highlight'] = get_highlight_query_analyzer(["name", "description"], query)

        logging.info("get get_es_query:%s" % q)

        res = es_query('newwiki', q, offset, size)

        return res
    except:
        logging.error("catch exception, query_sku:%s" % traceback.format_exc())
        return []


def get_zonghe_query(query, synonym_term_list):
    try:

        query_list = copy.deepcopy(synonym_term_list)
        query_list.append(query)

        # 先获取该query词的百科
        q = {}
        q["query"] = {
            "function_score": {
                "query": {
                    "bool": {
                        "minimum_should_match": 1,
                        "should": [{
                            "terms": {
                                "name_pre": query_list
                            }
                        }, {
                            "term": {
                                "tag_not_analyzed": query
                            }
                        }, {
                            "term": {
                                "other_name_pre": query
                            }
                        }, {
                            "multi_match": {
                                'query': query,
                                'type': 'best_fields',
                                'operator': 'and',
                                'fields': ["name_pre", "other_name_pre", "tag_not_analyzed"],
                                "analyzer": "gm_default_index"
                            }
                        }],
                        "must_not": {
                            "term": {
                                "description": "none"
                            }
                        },
                        "must": {
                            "term": {
                                "is_online": True
                            }
                        },
                    }},
                "score_mode": "sum",
                "boost_mode": "sum",
                "functions": [
                    {
                        "filter": {
                            "term": {
                                "name_pre": query
                            }
                        },
                        "weight": 100
                    },
                    {
                        "filter": {
                            "terms": {
                                "name_pre": synonym_term_list
                            }
                        },
                        "weight": 30
                    },
                    {
                        "filter": {
                            "term": {
                                "other_name_pre": query
                            }
                        },
                        "weight": 50
                    },
                    {
                        "filter": {
                            "term": {
                                "tag_not_analyzed": query
                            }
                        },
                        "weight": 20
                    },
                ]
            }
        }
        q['highlight'] = get_highlight_query_analyzer(["name"], query)

        logging.info("get get_zonghe_query:%s" % q)

        res = es_query('newwiki', q, 0, 1)

        return res

    except:
        logging.error("catch exception, query_sku:%s" % traceback.format_exc())

        return []

@bind('doris/search/query_wiki_card')
def get_collect_wiki_card(query=""):
    try:
        all_data = {}
        redis_key_prefix = "doris_wiki:wiki_card_collect"
        results = redis_client.hget(redis_key_prefix, hashlib.md5(query.encode("utf-8")).hexdigest())
        if results:
            result = json.loads(results.decode("utf-8"))
            result_collect = result if result else []
            is_online_wiki = []
            for item in result_collect["wiki"]:
                if item["name"] != None:
                    is_online = NewItemWiki.objects.filter(id=item["id"]).values_list("is_online", flat=True).first()
                    logging.info("get is_online:%s" % is_online)
                    if is_online != False or None:
                        is_online_wiki.append(item)
            logging.info("get is_online_wiki:%s " % is_online_wiki)
            all_data["wiki"] = is_online_wiki
            all_data["id"] = result_collect["id"]
            if len(all_data["wiki"]) >= 4:
                return all_data

        return {}
    except:
        logging.error("catch exception, query_sku:%s" % traceback.format_exc())
        return {}


class NewItemWiki(models.Model):
    class Meta:
        verbose_name = u'项目新百科'
        db_table = 'wiki_item'
        app_label = 'gaia'

    id = models.IntegerField(verbose_name=u'百科ID', primary_key=True)
    is_online = models.BooleanField(u'是否上线', default=True)
