#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals, absolute_import, print_function

import datetime
import time

from django.conf import settings
from django.db import transaction

from gm_types.error import ERROR
from gm_types.gaia import (
    TAG_TYPE,
    TOPIC_TYPE,
    IMAGE_TYPE,
    DIARY_OPERATE,
    DIARY_OPERATION,
    PROBLEM_REVIEW_STATUS_CHOICES,
)
from gm_types.user_hierarchy import EventType

from live.tasks import (
    upload_video_picture_to_qiniu_v2,
    set_water_mark_to_video,
    set_clipping_to_video,
)
from talos.cache.takesofacache import take_sofa_cache
from talos.libs.diaryrank_utils import DiaryRankTool
from talos.manager.diary import set_diary_postoperation_cover
from talos.models import Draft
from talos.models.diary import (
    DiaryTag,
    DiaryExtra,
    PreOperationImage,
)
from talos.models.topic import (
    Problem,
    TopicImage,
    ProblemTag,
    Video,
)
from talos.services import (
    OrderService,
    TagService,
)
from talos.tasks.topic import push_diary_update_to_follow, add_doctor_topic
from talos.tasks.vote import process_topic_vote_for_create
from user_hierarchy.portal import process_task
from utils.rpc import rpc_client, logging_exception, gen


def create_topic_for_batch(
        user,
        diary,
        topic_list=[],
        tag_ids=[],
        device_id=None,
):
    """
    批量 创建 日记贴
    :param user:
    :param diary:
    :param topic_list:
    :param tag_ids:
    :param device_id:
    :return:
    """

    result = {
        'point_value': 0,
        'growth_value': 0,
        'submit_count': 0,
        'topic_ids': [],
    }

    try:
        with transaction.atomic():
            data = create_topic(topic_list, diary, user, device_id, result)
            topic_id_list = data.get("topic_id_list", [])
            need_add_video_tag_topic_ids = data.get("need_add_video_tag_topic_ids", [])
            video_id_list = data.get("video_id_list", [])
            result = data.get("result")
            topic_add_tags_and_diary_sync(diary, user, tag_ids, topic_id_list, need_add_video_tag_topic_ids)

        diary_or_video_update_and_push_func(diary, user, topic_id_list, video_id_list)
        result["topic_ids"] = topic_id_list
        return result

    except Exception as e:
        logging_exception()
        return gen(ERROR.CONTENT_CREATE_ERROR)


def _set_review_status(topic_content, topic_images):
    """

    :param content:
    :param images:
    :return:
    """
    if len(topic_content) < settings.CASHBACK_TOPIC_CONTENT_WORDS_LIMIT or len(
            topic_images) < settings.CASHBACK_TOPIC_IMAGE_LIMIT:
        review_status = PROBLEM_REVIEW_STATUS_CHOICES.CONTENT_LIMIT
    else:
        review_status = PROBLEM_REVIEW_STATUS_CHOICES.NOT_REVIEW

    return review_status


def create_topic(topic_list, diary, user, device_id, result):
    """
    日记贴创建 及 日记本 术前术后图更新
    :param topic_list:
    :param diary:
    :param user:
    :param device_id:
    :param result:
    :return:
    """
    has_added_user_growth_value = False  # 是否已经增加了用户的成长值
    can_update_diary_info = False  # 能否更新日记本信息
    diary_pre_cover_list = []  # 日记本术前封面图
    diary_post_cover_list = []  # 日记本术后封面图
    topic_id_list = []  # 批量创建的帖子id列表
    need_add_video_tag_topic_ids = []  # 需要增加视频标签的帖子id
    video_id_list = []  # 为了异步更新视频图片

    topic_exists = Problem.objects.filter(diary_id=diary.id).exists()  # 该日记本下是否存在过帖子

    _data = {
        "topic_id_list": topic_id_list,
        "need_add_video_tag_topic_ids": need_add_video_tag_topic_ids,
        "video_id_list": video_id_list,
        "result": result,
    }

    for topic_item in topic_list:
        content = topic_item.get("content", "")
        images = topic_item.get("images", [])
        pre_cover = topic_item.get("pre_cover", "")  # 术前封面
        post_cover = topic_item.get("post_cover", "")  # 术后封面
        operation_timestamp = float(topic_item.get("operation_timestamp", 0))
        operation_date = datetime.date.fromtimestamp(
            operation_timestamp) if operation_timestamp else datetime.date.today()

        video_url = topic_item.get("video", "")
        draft_id = topic_item.get("draft_id", "")

        # 创建 日记帖
        if images or content.strip() or video_url:  # v 7.7.25 pm 要求通过 内容、图片、视频 三者判断有其一即可!
            topic_create_dict = {
                "answer": content,
                "diary_id": diary.id,
                "user_id": user.id,
                "topic_type": TOPIC_TYPE.SHARE,
                "device_id": device_id if device_id else None,
                "operation_date": operation_date,
                "review_status": _set_review_status(content, images)
            }
            topic = Problem.objects.create(**topic_create_dict)
            topic_id_list.append(topic.id)

            # 传视频
            if video_url != "" and user.can_create_video:
                video_url = Video.cleaned_video_url(video_url)
                video, _ = Video.objects.get_or_create(video_url=video_url, topic_id=topic.id, video_pic="")
                video_id_list.append(video.id)  # 事物操作结束，异步更新封面图
                need_add_video_tag_topic_ids.append(topic.id)

            # 成长值相关
            if not has_added_user_growth_value and len(content.strip()) >= 30 and len(images) >= 3:
                event_data = process_task(user_id=user.id, event_type=EventType.CREATE_TOPIC,
                                          related_item=topic.id)
                result.update({
                    'point_value': event_data['point_value'],
                    'growth_value': event_data['growth_value'],
                    'submit_count': event_data['submit_count'],
                })
                has_added_user_growth_value = True

            # 术前封面图相关
            if pre_cover:
                diary_pre_cover_list.append(pre_cover)

            # 术后封面图相关
            if post_cover:
                diary_post_cover_list.append(post_cover)

            # 处理图片
            post_operation_images_list = []  # 批量创建术后图列表
            for image in images:
                if 'image' not in image:
                    # seems like client has bugs when uploading images
                    continue

                timestamp = image.get('timestamp', None)

                if timestamp:
                    taken_time = datetime.datetime.fromtimestamp(int(timestamp))
                else:
                    taken_time = datetime.datetime.now()

                post_operation_images_list.append(
                    TopicImage(topic_id=topic.id, image_url=image['image'], taken_time=taken_time))

            if post_operation_images_list:
                TopicImage.objects.bulk_create(post_operation_images_list)

            # 更新日记本信息开关
            if not can_update_diary_info:
                can_update_diary_info = True

            # 点赞灌水统一后，老版本灌水逻辑弃用(日记帖创建)
            # 处理日记贴创建后的数据放大
            # process_topic_vote_for_create(topic.id)

            # 删除草稿
            if draft_id:
                try:
                    draft = Draft.objects.get(pk=draft_id, diary_id=diary.id)
                    # 草稿发布，修改日记本状态
                    if draft and not diary.is_online and not topic_exists:
                        diary.is_online = True
                        diary.save()
                    draft.delete()
                except Draft.DoesNotExist:
                    pass

    now = datetime.datetime.now()
    # 更新日记本信息操作
    if can_update_diary_info:

        # 更新术后相册
        if diary_post_cover_list:
            diary.post_operation_image = diary_post_cover_list[-1]
            set_diary_postoperation_cover(diary_post_cover_list[-1], diary)

        # 更新术前相册，仅在没有术前封面的情况下才更新
        if not diary.pre_operation_image and diary_pre_cover_list:
            diary.pre_operation_image = diary_pre_cover_list[0]

        diary.last_modified = now
        diary.last_topic_add_time = diary.last_modified
        diary.save()

    return _data


def topic_add_tags_and_diary_sync(diary, user, tag_ids, topic_id_list, need_add_video_tag_topic_ids):
    """
    给所有日记帖添加标签，日记本同步标签
    :param diary:
    :param user:
    :param tag_ids:
    :param topic_id_list:
    :param need_add_video_tag_topic_ids:
    :return:
    """
    # 处理标签
    tag_ids = list(map(int, tag_ids))
    diary_tag_ids = list(DiaryTag.objects.filter(diary_id=diary.id).values_list("tag_id", flat=True))
    topic_bind_tag_ids = []  # 帖子需要绑定的标签
    diary_exist_tag_ids = set()  # 日记本已有的标签，用于是否需要帖子相关标签同步
    tag_ids.extend(diary_tag_ids)  # 帖子需要同步日记本的标签，所以拼接上日记本的标签

    # 标签筛选, 并不是所有的帖子都需要打上视频标签
    if settings.VIDEO_TAG_ID in tag_ids:
        tag_ids.remove(settings.VIDEO_TAG_ID)

    has_geo_tag = False
    try:
        tags = TagService.get_tags_by_tag_ids(tag_ids)
    except Exception as e:
        raise gen(ERROR.CONTENT_CREATE_ERROR)

    tags = sorted(tags, key=lambda tag_item: tag_ids.index(tag_item.id))
    for t in tags:
        if t.tag_type in (TAG_TYPE.COUNTRY, TAG_TYPE.PROVINCE):
            continue

        if t.tag_type == TAG_TYPE.CITY:
            has_geo_tag = True

        if t.id not in topic_bind_tag_ids:
            topic_bind_tag_ids.append(t.id)

        if t.id in diary_tag_ids and t.id != settings.VIDEO_TAG_ID \
                and t.tag_type not in [TAG_TYPE.COUNTRY, TAG_TYPE.PROVINCE, TAG_TYPE.CITY]:
            diary_exist_tag_ids.add(t.id)

    if not has_geo_tag and user.city_tag_id and user.city_tag_id not in topic_bind_tag_ids:
        topic_bind_tag_ids.append(user.city_tag_id)

    can_sync_tag_ids = []  # 日记本标签同步
    topic_tag_create_list = []  # 帖子标签创建同步

    # 如果有视频，就给日记本和对应帖子 添加视频日记的tag
    if need_add_video_tag_topic_ids:
        can_sync_tag_ids.append(settings.VIDEO_TAG_ID)
        topic_tag_create_list.extend(
            [ProblemTag(problem_id=topic_id, tag_id=settings.VIDEO_TAG_ID) for topic_id in need_add_video_tag_topic_ids])

    topic_tag_create_list.extend(
        [ProblemTag(problem_id=topic_id, tag_id=tag_id) for topic_id in topic_id_list for tag_id in topic_bind_tag_ids])

    # 帖子标签批量创建
    ProblemTag.objects.bulk_create(topic_tag_create_list)

    if len(diary_exist_tag_ids) < settings.DIARY_TAGS_MAX_COUNT:
        _count = settings.DIARY_TAGS_MAX_COUNT - len(diary_exist_tag_ids)
        can_sync_tag_ids.extend(sorted(set(topic_bind_tag_ids) - set(diary_tag_ids), key=topic_bind_tag_ids.index)[:_count])

    if can_sync_tag_ids:
        diary.add_tags(can_sync_tag_ids)


def diary_or_video_update_and_push_func(diary, user, topic_id_list, video_id_list):
    """
    :param diary:
    :param user:
    :param topic_id_list:
    :param video_id_list: 更新视频的封面图
    :return:
    """
    # 发帖后 日记本的更新 及 推送
    d = DiaryRankTool(diary.id)
    d.add_heat(DIARY_OPERATION.CREATE_TOPIC, datetime.datetime.now())

    topics_num = Problem.objects.filter(diary_id=diary.id).count()
    if diary.doctor_id and topic_id_list:
        topic_info = {
            'id': topic_id_list[-1],
            'diary_id': diary.id,
            'nickname': user.nickname,
            'person_id': user.person_id,
            'related_service_name': diary.related_service_name,
            'title': diary.title,
            'service_id': diary.service_id,
            'operation_time': diary.operation_time.strftime('%Y-%m-%d') if diary.operation_time else '',
        }
        if topics_num >= 1:
            rpc_client['doctor/notify/create_topic'](doctor_id=diary.doctor_id, topic=topic_info,
                                                     count=topics_num).unwrap()

    if diary.order_id:
        # diary is related to an order create cashback order
        OrderService.create_cashback_order_by_order_id(diary.order_id)

    if topics_num >= 1 and diary.reply_num == 0:
        # add diary_id to take_sofa diary_id list
        create_time = time.mktime(diary.last_modified.timetuple())
        take_sofa_cache.set_diary_cache_data(create_time, diary.id)

    diary_extra, _ = DiaryExtra.objects.get_or_create(diary=diary)

    # 更新视频封面，放在事物外处理
    if video_id_list:
        for video_id in video_id_list:
            upload_video_picture_to_qiniu_v2.delay(video_id)
            set_water_mark_to_video.delay(video_id)
            # set_clipping_to_video.delay(video_id)

    # 记录操作 ADD_TOPIC  只记录最新一个日记帖id
    if topic_id_list:
        diary.set_diary_operate(DIARY_OPERATE.ADD_TOPIC, topic_id_list[-1])

    # push
    push_diary_update_to_follow.delay(diary.id, diary.user_id, diary.title)

    # 和医生建立关系，医生后台可见
    add_doctor_topic.delay(topic_id_list, user.id)