import operator
import datetime
from urllib.parse import urljoin
from collections import defaultdict
from django.db.models import Q, Sum, Count, F
from django.utils import timezone
from django.conf import settings

from gm_types.error import ERROR as CODES
from gm_types.mimas import (
    TRACTATE_PLATFORM,
    TRACTATE_STATUS,
    SOFT_ARTICLE_RELATION_TYPE,
    SOFT_ARTICLE_TYPE,
)
from gm_types.gaia import DOCTOR_TYPE
from gm_dataquery.dict_mixin import to_dict

from .base import BaseService
from utils.rpc import gen
from talos.libs.datetime_utils import get_timestamp_or_none
from social.models import SocialInfo
from talos.models.soft_article.reply import SoftArticleReply
from talos.models.soft_article.check import SoftArticleCheck
from talos.models.soft_article.soft_article import (
    SoftArticle, SoftArticleExtra, SoftArticleImages,
    SoftArticleRelation, SoftArticleVideo
)
from talos.services.tag import TagService
from talos.models.diary.diary import Diary
from talos.services.goods import GoodsService
from talos.cache.base import soft_article_vote_count_cache, soft_article_favor_count_cache, soft_article_pv_cache
from talos.services import UserService, get_user_from_context, DoctorService

from talos.tasks.tractate import set_softarticle_video_water_mark_url

from talos.rpc import gen


def filter_ids(ids):
    return list(map(int, filter(None, ids)))


class SoftArticleService(BaseService):
    model = SoftArticle
    audit_can_show_status = [
        TRACTATE_STATUS.AUDIT_SUCCESS,
    ]
    base_query = Q(is_online=True, status__in=audit_can_show_status, hera_is_online=True)

    @classmethod
    def healthy(cls, softarticle_id):

        softarticle = cls.get_by_id(softarticle_id)
        if not softarticle:
            gen(CODES.TRACTATE_NOT_FOUND)

        return softarticle

    @classmethod
    def incr_article_reply(cls, soft_article_id):
        try:
            te = SoftArticleExtra.objects.get(softarticle_id=soft_article_id)
        except SoftArticleExtra.DoesNotExist:
            te = SoftArticleExtra.objects.create(softarticle_id=soft_article_id)

        te.reply_count = te.reply_count + 1
        te.save(update_fields=['reply_count'])

    @classmethod
    def dec_article_reply(cls, soft_article_id):
        try:
            te = SoftArticleExtra.objects.get(softarticle_id=soft_article_id)
        except SoftArticleExtra.DoesNotExist:
            te = SoftArticleExtra.objects.create(softarticle_id=soft_article_id)

        te.reply_count = te.reply_count - 1
        te.save(update_fields=['reply_count'])

    @classmethod
    def get_article_reply(cls, soft_article_id):
        try:
            reply_count = SoftArticleExtra.objects.get(softarticle_id=soft_article_id).reply_count
        except:
            reply_count = 0

        return reply_count

    @classmethod
    def update_article_reply(cls, softarticle_id, new_reply_count):
        SoftArticleExtra.objects.update_or_create(
            softarticle_id=softarticle_id,
            defaults={"reply_count": new_reply_count},
        )

    @classmethod
    def get_base_info(cls, softarticle):
        return {
            'softarticle_id': softarticle.id,
            'doctor_id': softarticle.doctor_id,
            'merchant_id': softarticle.merchant_id,
            'title': softarticle.title,
            'content': softarticle.content,
            'is_online': softarticle.is_online,
            'status': softarticle.status,
            "hera_is_online": softarticle.hera_is_online,
            'content_level': softarticle.content_level,
            'create_timestamp': int(softarticle.create_time.strftime("%s")),
            'view_amount': softarticle.view_amount,
            'favor_amount': softarticle.favor_amount,
            "vote_amount": softarticle.vote_amount,
            "reply_amount": softarticle.reply_amount,
            "show_order": softarticle.show_order,
            "article_type": softarticle.article_type,
            "video_url": "",
            "doctor_name": "",
            "reason": "",
        }

    @classmethod
    def create(self, merchant_id, content, doctor_id, title, article_type, extra={}):
        if not doctor_id:
            return gen(CODES.DOCTOR_NOT_FOUND)

        image_url = extra.get("img_url")
        video_url = extra.get("video_url")

        tag_ids = extra.get("tag_ids", [])
        service_id = extra.get("service_id")
        diary_id = extra.get("diary_id")

        article = self.model()
        article.content = content
        article.doctor_id = doctor_id
        article.title = title
        article.merchant_id = merchant_id
        article.platform = TRACTATE_PLATFORM.DOCTOR
        article.article_type = article_type
        article.save()

        SoftArticleCheck.objects.create(softarticle_id=article.id, status=TRACTATE_STATUS.UNAUDITED)
        relations = []    #Todo更美type修改
        if service_id:
            relations.append(SoftArticleRelation(softarticle_id=article.id, relation_id=service_id,
                                                 relation_type=SOFT_ARTICLE_RELATION_TYPE.SERVICE))

        if diary_id:
            relations.append(SoftArticleRelation(softarticle_id=article.id, relation_id=diary_id,
                                                 relation_type=SOFT_ARTICLE_RELATION_TYPE.DIARY))

        if tag_ids:
            for tag_id in tag_ids:
                relations.append(SoftArticleRelation(softarticle_id=article.id, relation_id=tag_id,
                                                     relation_type=SOFT_ARTICLE_RELATION_TYPE.TAG))

        SoftArticleRelation.objects.bulk_create(relations)

        if video_url and article.article_type == SOFT_ARTICLE_TYPE.VIDEO:
            vo = SoftArticleVideo.objects.create(softarticle_id=article.id,
                                                 upload_img_cover=image_url,
                                                 raw_video_url=SoftArticleVideo.cleaned_video_url(video_url))
            set_softarticle_video_water_mark_url.delay(vo.id)

        if image_url and article.article_type == SOFT_ARTICLE_TYPE.ORDINARY:
            SoftArticleImages.objects.create(softarticle_id=article.id, image_url=image_url)

        return article.id

    @classmethod
    def update(cls, merchant_id, soft_article_id, content, doctor_id, title, extra={}):
        if not soft_article_id:
            return gen(CODES.PARAMS_INCOMPLETE)

        article = cls.model.objects.filter(id=soft_article_id).first()

        if not article:
            return gen(CODES.PARAMS_INCOMPLETE)

        article.content = content
        article.doctor_id = doctor_id
        article.title = title
        article.platform = TRACTATE_PLATFORM.DOCTOR
        article.merchant_id = merchant_id
        article.status = TRACTATE_STATUS.UNAUDITED
        article.save()

        SoftArticleCheck.objects.update_or_create(softarticle_id=article.id, defaults={"status": TRACTATE_STATUS.UNAUDITED})

        image_url = extra.get("img_url", [])
        video_url = extra.get("video_url")

        tag_ids = extra.get("tag_ids", [])
        service_id = extra.get("service_id")
        diary_id = extra.get("diary_id")

        relations = SoftArticleRelation.objects.filter(softarticle_id=article.id).values()
        r_dic, del_ids = [], []
        for item in relations:
            if item.get('relation_type') == 2:     #美购ID
                if item.get('relation_id') != int(service_id):
                    r_dic.append(SoftArticleRelation(softarticle_id=article.id, relation_id=service_id,
                                                     relation_type=2))
                    del_ids.append(item.get('relation_id'))

            if item.get('relation_type') == 3:     #日记本ID
                if item.get('relation_id') != int(diary_id):
                    r_dic.append(SoftArticleRelation(softarticle_id=article.id, relation_id=diary_id,
                                                     relation_type=3))
                    del_ids.append(item.get('relation_id'))

            if item.get('relation_type') == 1:  # TAG ID
                if item.get('relation_id') not in tag_ids:
                    del_ids.append(item.get('relation_id'))
                else:
                    tag_ids.remove(item.get('relation_id'))

        for tag_id in tag_ids:
            r_dic.append(SoftArticleRelation(softarticle_id=article.id, relation_id=tag_id,
                                             relation_type=1))

        SoftArticleRelation.objects.bulk_create(r_dic)
        SoftArticleRelation.objects.filter(id__in=del_ids).delete()

        if image_url and article.article_type == SOFT_ARTICLE_TYPE.ORDINARY:
            img_info, status = SoftArticleImages.objects.get_or_create(softarticle_id=article.id)
            if status and img_info.image_url != image_url:
                img_info.image_url = image_url
                img_info.save()

        if video_url and article.article_type == SOFT_ARTICLE_TYPE.VIDEO:
            video_info, status = SoftArticleVideo.objects.get_or_create(softarticle_id=article.id)
            video_url = SoftArticleVideo.cleaned_video_url(video_url)
            if status and video_info.raw_video_url != video_url:
                video_info.raw_video_url = video_url
                video_info.save()
                set_softarticle_video_water_mark_url.delay(video_info.id)

        return article.id

    @classmethod
    def inc_soft_article_vote(cls, softarticle_id):
        te, _ = SoftArticleExtra.objects.get_or_create(softarticle_id=softarticle_id)
        te.vote_count = F('vote_count') + 1
        te.save(update_fields=['vote_count'])
        return soft_article_vote_count_cache.incrby(str(softarticle_id), 1)

    @classmethod
    def dec_soft_article_vote(cls, softarticle_id):
        te, _ = SoftArticleExtra.objects.get_or_create(softarticle_id=softarticle_id)
        if te.vote_count > 0:
            te.vote_count = F('vote_count') - 1
            te.save(update_fields=['vote_count'])

        vote_cache_count = int(soft_article_vote_count_cache.get(str(softarticle_id)) or 0)
        if vote_cache_count > 0:
            return soft_article_vote_count_cache.decr(str(softarticle_id), 1)
        return vote_cache_count

    @classmethod
    def inc_soft_article_favor(cls, softarticle_id):
        try:
            te = SoftArticleExtra.objects.get(softarticle_id=softarticle_id)
        except SoftArticleExtra.DoesNotExist:
            te = SoftArticleExtra.objects.create(softarticle_id=softarticle_id)

        te.favor_count = F('favor_count') + 1
        te.save(update_fields=['favor_count'])
        return soft_article_favor_count_cache.incrby(str(softarticle_id), 1)

    @classmethod
    def dec_soft_article_favor(cls, softarticle_id):
        try:
            te = SoftArticleExtra.objects.get(softarticle_id=softarticle_id)
        except SoftArticleExtra.DoesNotExist:
            te = SoftArticleExtra.objects.create(softarticle_id=softarticle_id)
        if te.favor_count > 0:
            te.favor_count = F('favor_count') - 1
            te.save(update_fields=['favor_count'])

        favor_cache_count = int(soft_article_favor_count_cache.get(str(softarticle_id)) or 0)
        if favor_cache_count > 0:
            return soft_article_favor_count_cache.decr(str(softarticle_id), 1)
        return favor_cache_count

    @classmethod
    def soft_article_view_increase_num(cls, softarticle_ids):
        for _id in softarticle_ids:
            soft_article_pv_cache.incrby(str(_id), 1)

    @classmethod
    def get_video_infos(cls, softarticle_ids):
        result = {}
        if not softarticle_ids:
            return result

        s_videos = SoftArticleVideo.objects.filter(softarticle_id__in=softarticle_ids, is_online=True)\
                                           .values("softarticle_id", "raw_video_url", "water_video_url",
                                                   "video_cover_url", "upload_img_cover")

        for video in s_videos:
            s_id = video.get("softarticle_id")
            if s_id not in result:
                result[s_id] = []
            _video_url = video.get("water_video_url", "") or video.get("raw_video_url", "") or ""
            _video_data = {
                "video_url": urljoin(settings.VIDEO_HOST, _video_url),
                "video_cover_url": video.get("video_cover_url", ""),
            }
            result[s_id].append(_video_data)

        return result

    @classmethod
    def get_soft_article_by_ids(cls, soft_article_ids, doctor_id=None, need_special_info=False):
        """
        获取列表数据        Todo 还需要改
        :param soft_article_ids:
        :param doctor_id:
        :param need_special_info: 是否需要社交信息 (收藏，点赞，用户关注的状态)
        :return:
        """
        result = {
            "valid_soft_article_ids": [],
            "soft_article_list": []
        }
        if not soft_article_ids:
            return result

        soft_article_list = cls.list_objs_by_ids(soft_article_ids)
        _user_ids, valid_soft_article_ids = [], []
        for t, t_value in soft_article_list.items():
            _user_ids.append(t_value.user_id)
            valid_soft_article_ids.append(t_value.id)

        s_video_dic = cls.get_video_infos(valid_soft_article_ids)
        #获取关联信息  Todo
        s_relation_dic = cls.get_relation_data(valid_soft_article_ids)
        user_dic = UserService.get_users_by_user_ids(_user_ids)
        for s_key, soft_article_dic in soft_article_list.items():
            _soft_article_id = soft_article_dic.id
            _user_id = soft_article_dic.user_id
            user_info = user_dic.get(_user_id, {})
            video_item_list = s_video_dic.get(_soft_article_id, [])
            relation_info = s_relation_dic.get(_soft_article_id, {"tag_data": [], "service": {}, "diary": {}})
            base_data = cls.get_base_info(soft_article_dic)
            base_data.update({
                "videos": video_item_list,
                "user": {
                    "id": user_info.id,
                    "name": user_info.nickname,
                    "portrait": user_info.portrait,
                },
                "images": [],               #医生后台是富文本模式  图片文字混在一起
                'is_voted': False,
                'is_favored': False,
                'is_following': follow_rels.get(_user_id, False),
            })
            base_data.update(relation_info)
            result["soft_article_list"].append(base_data)
        result["valid_soft_article_ids"] = valid_soft_article_ids
        return result

    @classmethod
    def get_relation_data(cls, soft_article_ids):

        relations = SoftArticleRelation.objects.filter(softarticle_id__in=soft_article_ids)\
                                               .values('softarticle_id', 'relation_id', 'relation_type')

        tag_ids = [relation.get('relation_id') if relation.get('relation_type') == 1 else None for relation in
                   relations]

        tags_info = TagService.get_tags_by_tag_ids(ids=tag_ids)

        tag_data = {tag_info.id: tag_info for tag_info in tags_info}

        service_ids = [relation.get('relation_id') if relation.get('relation_type') == 2 else None for relation in
                       relations]
        service_infos = GoodsService.get_service_by_service_ids(service_ids)
        service_data = {service_info.get('id'): {
            "id": service_info.get('id'),
            "name": service_info.get('name'),
            "short_description": service_info.get('short_description'),
            "doctor": service_info.get('doctor'),
        } for service_info in service_infos}

        diary_ids = [relation.get('relation_id') if relation.get('relation_type') == 3 else None for relation in
                     relations]
        diary_infos = Diary.objects.filter(id__in=diary_ids).values('id', 'title')
        diary_dict = {}
        for diary in diary_infos:
            diary_dict[diary.get('id')] = diary.get('title')

        result = {}

        for relation in relations:
            s_id = relation.get('softarticle_id')
            r_id = relation.get('relation_id')

            if s_id not in result:
                result[s_id] = {'tag_data': [], 'service': {}, 'diary': {}}

            if relation.get('relation_type') == 1:  # 1就是tag了
                if tag_data.get(r_id):
                    result[s_id]['tag_data'].append({
                        'id': r_id,
                        'name': tag_data.get(r_id).name,
                        'type': tag_data.get(r_id).tag_type,
                    })

            if relation.get('relation_type') == 2:  # 2就是美购了
                result[s_id]['service'] = service_data.get(r_id)

            if relation.get('relation_type') == 3:  # 3就是日记本了
                result[s_id]['diary'] = {'id': r_id, 'title': diary_dict.get(r_id)}

        return result

    @classmethod
    def get_dict_by_soft_article_ids(cls, soft_article_ids):
        if not soft_article_ids:
            return {}

        result = {}
        articles = cls.model.objects.filter(id__in=soft_article_ids).values()
        for article in articles:
            article['create_time'] = article['create_time'].timestamp()
            article['online_time'] = article['online_time'].timestamp()
            article['last_modified'] = article['last_modified'].timestamp()
            result[article.get('id')] = article

        return result

    @staticmethod
    def get_follow_info(viewer_user_id, author_ids):
        """
        用户之间的关注状态
        :param viewer_user_id: 浏览用户
        :param author_ids: 作者列表
        :return:
        """
        follow_rels = {}
        if viewer_user_id:
            social_info = SocialInfo(uid=viewer_user_id)
            follow_rels = social_info.is_following_users(uids=author_ids)

        return follow_rels

    @staticmethod
    def get_image_info_by_ids(soft_article_ids):
        result = dict()
        soft_article_ids = filter_ids(soft_article_ids)
        if not soft_article_ids:
            return result

        images = SoftArticleImages.objects.filter(
            softarticle_id__in=soft_article_ids
        ).values("softarticle_id", "image_url", "width", "height")

        _result = defaultdict(list)
        for _image_item in images:
            soft_act_id = _image_item.get("softarticle_id", 0)
            _data = {
                'image_url': _image_item.get("image_url", ""),
                "width": _image_item.get("width", 0),
                "height": _image_item.get("height", 0)
            }
            _result[soft_act_id].append(_data)

        return dict(_result)

    @staticmethod
    def get_video_info_by_ids(soft_article_ids):
        """
        获取视频信息，列表与详情页展示不一致
        :param soft_article_ids:
        :return:
        """
        result = {}
        soft_article_ids = filter_ids(soft_article_ids)
        if not soft_article_ids:
            return result

        videos_info = SoftArticleVideo.objects.filter(
            softarticle_id__in=soft_article_ids,
            is_online=True
        ).values('softarticle_id', 'upload_img_cover', 'raw_video_url', 'water_video_url', "video_cover_url",
                 'width', 'height')

        for video_item in videos_info:
            soft_art_id = video_item.get("softarticle_id", 0)
            _video_url = video_item.get("water_video_url", "") or video_item.get("raw_video_url", "")
            _video_data = {
                "video_url": urljoin(settings.VIDEO_HOST, _video_url),
                "video_cover_url": video_item.get("video_cover_url", ""),
                "upload_img_cover": video_item.get("upload_img_cover", ""),
                "width": video_item.get("width", 0),
                "height": video_item.get("height", 0),
            }
            if soft_art_id not in result:
                result[soft_art_id] = []
            result[soft_art_id].append(_video_data)

        return dict(result)

    @staticmethod
    def get_doctor_info_by_doctor_ids(doctor_ids):
        result = dict()

        if doctor_ids:
            doctor_infos = DoctorService.get_doctor_from_doctor_ids(doctor_ids)
            for doctor_item in doctor_infos:
                _did = doctor_item.id
                _data = {
                    "doctor_id": _did,
                    "doctor_type": doctor_item.doctor_type,
                    "hospital_id": doctor_item.hospital_id if doctor_item.doctor_type == DOCTOR_TYPE.OFFICER else "",
                    "doctor_name": doctor_item.name,
                    "doctor_portrait": doctor_item.portrait,
                    "user_id": doctor_item.user_id,
                }
                result[_did] = _data

        return result

    @staticmethod
    def get_soft_article_relation_data(soft_article_ids, relation_type):
        """
        通过类型获取关联信息 目前仅仅处理了标签的数据，美购及日记本仅返回ID list, 需要的话在backend层再做封装
        :param soft_article_ids:
        :param relation_type: 枚举值，1，2，3
        :return:
        """
        result = dict()

        soft_article_ids = filter_ids(soft_article_ids)
        if not soft_article_ids:
            return result

        relations = SoftArticleRelation.objects.filter(
            softarticle_id__in=soft_article_ids,
            relation_type=relation_type
        ).values('softarticle_id', 'relation_id').distinct()

        if relation_type == SOFT_ARTICLE_RELATION_TYPE.TAG:  # 如果是标签，处理了下数据。美购和日记本在其他服务上通过id做转换
            _tag_ids = [relation["relation_id"] for relation in relations]
            tags_info = TagService.get_tags_by_tag_ids(_tag_ids)
            relation_data = {tag.id: {
                "id": tag.id,
                "name": tag.name,
                "tag_id": tag.id,
                "tag_name": tag.name,
                "tag_type": tag.tag_type,
            }for tag in tags_info}

        else:
            relation_data = {}

        result = defaultdict(list)
        for _item in relations:
            _s_id = _item.get("softarticle_id")
            _r_id = _item.get("relation_id")
            if relation_data:
                relation_info = relation_data.get(_r_id, {})
            else:
                relation_info = _r_id

            if relation_info and _s_id:
                result[_s_id].append(relation_info)

        return dict(result)

    @staticmethod
    def get_soft_article_relation_ids_by_soft_acticle_ids(soft_article_ids, relation_type):
        """
        通过类型及id获取关联的id,用于backend 调取其他服务拉取更多数据
        :param soft_article_ids:
        :param relation_type:
        :return:
        """
        result = {}
        soft_article_ids = filter_ids(soft_article_ids)

        if soft_article_ids:
            _result = defaultdict(list)
            relation_ids = SoftArticleRelation.objects.filter(
                softarticle_id__in=soft_article_ids,
                relation_type=relation_type
            ).values_list('softarticle_id', 'relation_id')

            for softarticle_id, relation_id in relation_ids:
                _result[str(softarticle_id)].append(relation_id)
            result = dict(_result)

        return result

    @classmethod
    def get_soft_article_objs_by_query_and_order(cls, query=Q(), order_by=[], need_section=False, **kwargs):
        """
        通过query和order获取帖子对象
        :param query:
        :param order_by:
        :param need_section: 是否需要切片
        :param kwargs: 其他字段数据
        :return:
        """
        soft_article_queryset = cls.model.objects.filter(query).order_by(*order_by)
        if need_section:
            offset = kwargs.get("offset", 0)
            size = kwargs.get("size", 10)
            soft_article_queryset = soft_article_queryset[offset: offset + size]
        return soft_article_queryset

    @staticmethod
    def sort_objects_by_pk_list(queryset, pk_list):
        """
        按照id做展示顺序
        :param queryset:
        :param pk_list:
        :return:
        """
        return sorted(queryset, key=lambda obj: pk_list.index(obj.id))

    @classmethod
    def get_soft_article_objs_by_ids(cls, soft_article_ids, query=Q()):
        """
        通过id列表获取有序的queryset类型数据
        :param soft_article_ids:
        :param query:
        :return:
        """
        _soft_article_ids = filter_ids(soft_article_ids)
        if not query:
            query = cls.base_query
        filter_query = Q(pk__in=_soft_article_ids) & query

        soft_article_queryset = cls.get_soft_article_objs_by_query_and_order(query=filter_query)
        return cls.sort_objects_by_pk_list(soft_article_queryset, _soft_article_ids)

    @classmethod
    def _soft_article_assemble_data(cls, obj_list, need_special_info=False, display_for_detail=False, **kwargs):
        """
        数据转换的方法
        :param obj_list:
        :param need_special_info: 是否需要社交信息
        :param display_for_detail: 详情页展示 or 列表展示 bool值
        :param kwargs:
        :return:
        """

        result = {
            "soft_article_list": [],
            "valid_soft_article_ids": [],
        }

        if not obj_list:
            return result

        doctor_ids, valid_soft_article_ids = [], []
        for _soft_item in obj_list:
            doctor_ids.append(_soft_item.doctor_id)
            valid_soft_article_ids.append(_soft_item.id)

        doctor_info_dic = cls.get_doctor_info_by_doctor_ids(doctor_ids)
        follow_rels = {}
        if need_special_info:
            # 注意关注信息是依赖于user_id实现的，所以需要这样搞一波
            user_id = kwargs.get("user_id", 0)
            _user_ids = list(
                filter(None, [doctor_dic.get("user_id", 0) for doctor_dic in list(doctor_info_dic.values())]))
            if user_id:
                follow_rels = cls.get_follow_info(viewer_user_id=user_id, author_ids=_user_ids)
        else:
            follow_rels = {}

        video_dic = cls.get_video_info_by_ids(valid_soft_article_ids)
        tags_dic = cls.get_soft_article_relation_data(valid_soft_article_ids, relation_type=SOFT_ARTICLE_RELATION_TYPE.TAG)

        if display_for_detail:
            services_dic = cls.get_soft_article_relation_data(valid_soft_article_ids, relation_type=SOFT_ARTICLE_RELATION_TYPE.SERVICE)
            diaries_dic = cls.get_soft_article_relation_data(valid_soft_article_ids, relation_type=SOFT_ARTICLE_RELATION_TYPE.DIARY)
            images_dic = dict()
        else:
            images_dic = cls.get_image_info_by_ids(valid_soft_article_ids)
            services_dic = dict()
            diaries_dic = dict()

        for soft_article in obj_list:
            _soft_id = soft_article.id
            _did = soft_article.doctor_id

            doctor_info = doctor_info_dic.get(_did, {})
            _user_id = doctor_info.get("user_id", 0)

            video_item_list = video_dic.get(_soft_id, [])
            tag_info = tags_dic.get(_soft_id, [])
            base_data = cls.get_base_info(soft_article)

            base_data.update({
                "videos": video_item_list,
                "doctor": doctor_info,
                "tags": tag_info,
                "images": images_dic.get(_soft_id, []),
                "service_ids": services_dic.get(_soft_id, []),
                "diary_ids": diaries_dic.get(_soft_id, []),
                'is_voted': False,
                'is_favored': False,
                'is_following': follow_rels.get(int(_user_id), False),
            })

            result["soft_article_list"].append(base_data)
        result["valid_soft_article_ids"] = valid_soft_article_ids

        return result

    @classmethod
    def get_soft_article_info_for_card_by_obj_list(cls, obj_list, user_id=None, need_special_info=False):
        """
        为列表页卡片类数据展示准备的拼装方法
        :param obj_list:
        :param user_id:
        :param need_special_info:
        :return:
        """
        result = cls._soft_article_assemble_data(
            obj_list,
            need_special_info=need_special_info,
            user_id=user_id
        )
        return result

    @classmethod
    def get_soft_article_info_for_detail_by_obj_list(cls, obj_list, user_id=None, need_special_info=False):
        """
        为详情页展示，准备的拼装方法。由于详情页是富文本内容，图片相关的数据不再详情页展示，仅拉取视频的数据
        :param obj_list:
        :param user_id:
        :param need_special_info: 是否需要社交信息，处理用户关注的逻辑
        :return:
        """
        result = cls._soft_article_assemble_data(
            obj_list,
            need_special_info=need_special_info,
            display_for_detail=True,
            user_id=user_id
        )
        return result