# coding:utf-8

"""小组相关push"""
import copy
import json
import random
from datetime import datetime, date

from bs4 import BeautifulSoup
from django.conf import settings
from gm_types.doris.enum import CONTENT_AGGRE_CARD_TYPE
from gm_types.gaia import (
    TAG_TYPE,
    TAG_ATTRIBUTE,
    AGILE_TAG_ATTRIBUTE,
)

from rpc.context import get_rpc_remote_invoker
from rpc.cache import group_cache

from group.models import GroupFollow
from group.service import GroupService


def get_text_from_rich_text(content):
    """
    富文本 提取文本内容
    """
    content = copy.deepcopy(content)
    result = []
    if not content:
        return ""
    element_obj = BeautifulSoup(content, 'lxml')
    for tag in element_obj.find_all(True):
        tag_name = tag.name
        if not any([tag.string, tag.attrs]):
            continue
        if tag.string:
            result.append(str(tag.string))
    result = ''.join(result)
    return result


class GroupFollowPush(object):
    """小组关注用户push"""

    rpc = get_rpc_remote_invoker()

    push_groups = [1, 2, 3, 4, 5]

    cache = group_cache
    group_follow_cache_key_tpl = "group_follow_cache:{group_id}"
    group_card_today_pushed_user_key_tpl = "pushed_users{today}:{group_id}:{content_type}:{content_id}"
    pushed_user_key_tpl = "pushed_users"

    @classmethod
    def get_tag_type(cls, tag_type, is_agile=False):

        if not is_agile:
            if tag_type in [
                TAG_TYPE.BODY_PART,
                TAG_TYPE.BODY_PART_SUB_ITEM,
                TAG_TYPE.ITEM_WIKI
            ]:
                return TAG_ATTRIBUTE.ITEM
            else:
                return TAG_ATTRIBUTE.NO_ITEM
        else:
            if tag_type == AGILE_TAG_ATTRIBUTE.ITEM:
                return TAG_ATTRIBUTE.ITEM
            else:
                return TAG_ATTRIBUTE.NO_ITEM

    @classmethod
    def _classify_tags(cls, tags_info):
        """分类标签：当前标签列表、父标签列表、子标签列表。"""

        current_tags = []
        for item in tags_info.get("tags", []):
            current_tags.append({
                "id": item["id"],
                "name": item["name"],
                "type": cls.get_tag_type(item["tag_type"]),
                "is_new": False,
            })

        for item in tags_info.get("agile_tags", []):
            current_tags.append({
                "id": item["id"],
                "name": item["name"],
                "type": cls.get_tag_type(item["attribute"], is_agile=True),
                "is_new": True,
            })

        children_tags = []
        for item in tags_info.get("children", []):
            children_tags.append({
                "id": item["id"],
                "name": item["name"],
                "type": cls.get_tag_type(item["tag_type"]),
                "is_new": False,
            })

        parent_tags = []
        for item in tags_info.get("parent", []):
            parent_tags.append({
                "id": item["id"],
                "name": item["name"],
                "type": cls.get_tag_type(item["tag_type"]),
                "is_new": False,
            })

        return {
            "current_tags": current_tags,
            "parent_tags": parent_tags,
            "children_tags": children_tags,
        }

    @classmethod
    def _get_content_by_group_id(cls, group_id, top=6):
        """获取小组聚合页内容前 top 位"""

        try:
            group = GroupService.safe_get(group_id)
        except:
            return

        tags = GroupService.tags_by_group_id(group.id)
        if not tags:
            return

        tags_info = cls._classify_tags(tags)
        # 召回数据
        content_aggre_data = cls.rpc["doris/search/content_aggre_communit_sort"](
            current_tag=tags_info["current_tags"],
            sun_tag=tags_info["children_tags"],
            parent_tag=tags_info["parent_tags"],
            size=top,
            offset=0,
            is_video=False,
            is_group=True
        ).unwrap()

        content_aggre_data = content_aggre_data.get("content_aggre_sort", [])
        if not content_aggre_data:
            return

        content_aggre_data.update({
            "group_type": group.group_type
        })

        return content_aggre_data

    @classmethod
    def get_content_by_ids(cls):

        res = []
        for group_id in cls.push_groups:

            content = cls._get_content_by_group_id(group_id)
            if not content:
                continue

            for item in content:
                item["group_id"] = group_id
                res.append(item)

        res.sort(key=lambda i: -i.get("update_time", 0))

        return res

    @classmethod
    def del_group_follow(cls):
        """删除缓存"""

        for group_id in cls.push_groups:
            cls.cache.delete(
                cls.group_follow_cache_key_tpl.format(group_id=group_id),
            )

    @classmethod
    def del_pushed_user_key(cls):
        """删除本次已推送缓存"""
        cache_key = cls.pushed_user_key_tpl
        cls.cache.delete(cache_key)

    @classmethod
    def _add_group_follows_by_id(cls, group_id):
        """添加缓存"""

        today = date.today()
        min_time = datetime.min.time()
        today_start = datetime.combine(today, min_time)

        follows = list(
            GroupFollow.objects.using(settings.SLAVE_DB_NAME).filter(
                group_id=group_id, create_time__lt=today_start).values_list("user_id", flat=True)
        )
        cls.cache.set(
            cls.group_follow_cache_key_tpl.format(group_id=group_id),
            json.dumps(follows)
        )
        return follows

    @classmethod
    def get_group_follows_by_id(cls, group_id):
        """获取小组关注用户列表"""

        bfollow = cls.cache.get(
            cls.group_follow_cache_key_tpl.format(group_id=group_id),
        ) or '[]'
        bfollow = json.loads(bfollow)
        if not bfollow:
            follows = cls._add_group_follows_by_id(group_id)
            return set(follows)

        return set(bfollow)

    @classmethod
    def get_pushed_users(cls, group_id, content_type, content_id, today):
        """获取已经推送用户"""

        # 当前小组卡片今天已推送用户
        group_card_today_cache_key = cls.group_card_today_pushed_user_key_tpl.format(
            group_id=group_id, content_type=content_type,
            content_id=content_id, today=today,
        )

        # 本次已推送用户
        pushed_cache_key = cls.pushed_user_key_tpl

        return cls.cache.smembers(group_card_today_cache_key) | cls.cache.smembers(pushed_cache_key)

    @classmethod
    def record_push_users(cls, group_id, content_type, content_id, push_users, today):
        """记录推送用户"""

        # 当前小组卡片今天已推送用户
        cache_key = cls.group_card_today_pushed_user_key_tpl.format(
            group_id=group_id, content_type=content_type,
            content_id=content_id, today=today,
        )
        today = datetime.now()
        min_time = datetime.min.time()
        today_start = datetime.combine(today.date(), min_time)
        ex_seconds = int((today_start - today).seconds)

        if not cls.cache.exists(cache_key):
            cls.cache.expire(cache_key, ex_seconds)
        cls.cache.sadd(cache_key, *push_users)

        # 本次已推送用户
        cache_key = cls.pushed_user_key_tpl

        cls.cache.sadd(cache_key, *push_users)

    @classmethod
    def chioce_alert(cls,
        content_type, content, title=None,
        content_limit=40, title_limit=10,
    ):
        """生成文案"""

        alerts = {
            CONTENT_AGGRE_CARD_TYPE.DIARY: {
                "content": "「{content}」讨论中，等你来撩~",
            },
            CONTENT_AGGRE_CARD_TYPE.QA: {
                "title": "小组内容有更新，「{title}」，速去",
                "content": "{content}"
            },
            CONTENT_AGGRE_CARD_TYPE.TRACTATE: {
                "content": "「{content}」讨论中，等你来撩~",
            },
        }
        tpl = alerts[content_type]

        if len(content) > content_limit:
            content = content[:content_limit] + "..."
        content_tpl = tpl.get("content")
        content = get_text_from_rich_text(content)
        content = content_tpl.format(content=content)

        if title:
            if len(title) > title_limit:
                title = title[:title_limit] + "..."
            title_tpl = tpl.get("title")
            title = title_tpl.format(title=title)

        return content, title

    @classmethod
    def get_push_msg(cls, content_type, content_id):
        """获取相关push的内容，包括 title 和 content。"""

        title = content = None
        if content_type == CONTENT_AGGRE_CARD_TYPE.DIARY:
            diary_info = cls.rpc["diary/simple_data"](diary_id=content_id).unwrap()
            content, title = cls.chioce_alert(content_type, diary_info["title"])

        elif content_type == CONTENT_AGGRE_CARD_TYPE.TRACTATE:
            tractate_info = cls.rpc["mimas/tractate/get"](tractate_id=content_id).unwrap()
            content, title = cls.chioce_alert(content_type, tractate_info["content"])

        elif content_type == CONTENT_AGGRE_CARD_TYPE.QA:
            answer_info = cls.rpc["qa/answer/question_info"](answer_id=content_id).unwrap()
            content, title = cls.chioce_alert(
                content_type,
                content=answer_info["answer_content"],
                title=answer_info["question_title"],
                content_limit=40,
            )

        return {
            "title": title,
            "content": content,
        }
