
from functools import partial
from collections import defaultdict

from gm_types.error import ERROR as CODES

from utils.rpc import gen
from qa.services.base import ServiceBase
from qa.models import (
    QualityAuthorAnswer,
    QualityAuthorAnswerImage,
    QualityQuestionRead,
    QualityQuestion,
    QualityAnswerRead,
)
from talos.services import UserConvertService
from qa.services.base import ServiceModelCache
from qa.cache.cache_v2 import quality_question_cache
from utils.group_routine import GroupRoutine


class QualityAnswerService(ServiceBase):

    __cached_layer = partial(ServiceModelCache, quality_question_cache)

    @classmethod
    def health_get(cls, quality_answer_id):

        try:
            answer = QualityAuthorAnswer.objects.get(pk=quality_answer_id)
        except:
            return gen(CODES.QUALITY_ANSWER_NOT_FOUND)

        if not answer.is_online:
            return gen(CODES.QUALITY_ANSWER_OFFLINE)

        return answer

    @classmethod
    def create_answer(cls, quality_question_id, user_id, content, images):

        answer = QualityAuthorAnswer(
            quality_question_id=quality_question_id,
            user_id=user_id,
            content=content,
        )
        answer.save()

        answer_images = [
            QualityAuthorAnswerImage(
                quality_answer_id=answer.id,
                url=image["image"],
                width=image.get("width", 0),
                height=image.get("height", 0),
            )
            for image in images
        ]
        QualityAuthorAnswerImage.objects.bulk_create(answer_images)
        images = QualityAuthorAnswerImage.objects.filter(quality_answer_id=answer.id)

        return {
            "id": answer.id,
            "quality_answer_id": answer.id,
            "content": content,
            "images": [{"url": image.url} for image in images],
            "quality_question_id": quality_question_id,
            "user": {
                "id": user_id
            },
        }

    @classmethod
    def answers_by_quality_question_ids(cls, quality_question_ids, offset=0, count=10):

        # cache = cls.__cached_layer("answers_by_quality_question_ids")
        # cache_data = cache.mget(quality_question_ids)

        # missing = cache_data.pop(cache.missing_k)
        # if not missing:
        #     return cache_data

        routine = GroupRoutine()
        for quality_question_id in quality_question_ids:
            routine.submit(quality_question_id, cls.answers_by_question_id,
                           quality_question_id, offset, count)
        routine.go()

        quality_question_answers = {}
        for quality_question_id in quality_question_ids:
            quality_question_answers[quality_question_id] = routine.results.get(quality_question_id, [])

        user_ids = set()
        for _, answers in quality_question_answers.items():
            user_ids.update(set([answer["user"]["id"] for answer in answers]))
        users_dict = UserConvertService.get_user_info_by_user_ids(user_ids)

        for _, answers in quality_question_answers.items():
            for answer in answers:
                answer["user"].update(users_dict.get(answer["user"]["id"], {}))

        # cache.mset(quality_question_answers)
        # quality_question_answers.update(cache_data)

        return quality_question_answers

    @classmethod
    def answers_by_question_id(cls, quality_question_id, offset=0, count=10):

        qas = QualityAuthorAnswer.objects.filter(
            quality_question_id=quality_question_id
        ).order_by("-id")[offset: offset + count]

        answer_ids = [a.id for a in qas]
        images = QualityAuthorAnswerImage.objects.filter(quality_answer_id__in=answer_ids)
        images_dict = defaultdict(list)
        for image in images:
            images_dict[image.quality_answer_id].append({
                "url": image.url,
                "width": image.width,
                "height": image.height,
            })

        answers = []
        for answer in qas:
            answers.append({
                "id": answer.id,
                "content": answer.content,
                "quality_question_id": answer.quality_question_id,
                "quality_answer_id": answer.id,
                "user": {
                    "id": answer.user_id
                },
                "images": images_dict.get(answer.id, [])
            })

        return answers

    @classmethod
    def get_my_page_qa_unread_count(cls, user_id):
        result = {
            "favor_answer_unread_count": 0,
            "my_answer_unread_count": 0,
        }
        if not user_id:
            return result

        my_answer_unread_count = QualityQuestionRead.objects.filter(
            user_id=user_id, is_read=False
        ).count()
        favor_answer_unread_count = QualityAnswerRead.objects.filter(
            user_id=user_id, is_read=False
        ).count()
        result['favor_answer_unread_count'] = favor_answer_unread_count
        result['my_answer_unread_count'] = my_answer_unread_count

        return result

    @classmethod
    def my_page_answer_tab_read(cls, user_id):
        """
        我的页面-回答tab消息已读
        :param user_id:
        :return:
        """
        if not user_id:
            return

        QualityQuestionRead.objects.filter(user_id=user_id).update(is_read=True)

    @classmethod
    def my_page_favor_answer_tab_read(cls, user_id):
        """
        我的页面-收藏-回答tab消息已读
        :param user_id:
        :return:
        """
        if not user_id:
            return

        QualityAnswerRead.objects.filter(user_id=user_id).update(is_read=True)

    @classmethod
    def objs_by_ids(cls, answer_ids):

        if not answer_ids:
            return {}

        return QualityAuthorAnswer.objects.filter(pk__in=answer_ids).in_bulk(answer_ids)

    @classmethod
    def list_answer_by_ids(cls, ids):

        if not ids:
            return {}

        answers = QualityAuthorAnswer.objects.filter(pk__in=ids)
        quality_question_ids = [answer.quality_question_id for answer in answers]
        quality_questions = QualityQuestion.objects.filter(pk__in=quality_question_ids).in_bulk(quality_question_ids)

        result = {}
        for answer in answers:
            quality_question = quality_questions.get(answer.quality_question_id)
            result[answer.id] = {
                "answer_id": quality_question.answer_id,
                "content": answer.content,
                "create_time": answer.create_time,
                "is_online": answer.is_online,
                "user_id": answer.user_id,
                "quality_question_id": answer.quality_question_id,
            }

        return result
