# coding=utf-8

from datetime import datetime
import json

from django.conf import settings
from django.utils.html import escape
from django.db import IntegrityError

from api.models import Feedback
from api.models import FeedbackCategory
from api.models import FeedbackMessage
from api.models import FeedbackImage
from api.models import FEEDBACK_MESSAGE_TYPE
from api.models import FEEDBACK_RELATED_OBJECT_TYPE
from api.models import User, Person
from api.models import Order
from api.models import FunctionFeedback
from api.models import FeedbackQuestion
from api.models import FeedbackAnswer
from api.models import FeedbackUserSubmit
from api.models import UserVisitRecord
from api.models import FeedbackFunctionPeriod

from api.tool.datetime_tool import get_timestamp, get_timestamp_or_none
from api.tool.user_tool import get_user_from_context, get_user_extra_by_user_id
from api.tool.image_utils import get_full_path

from rpc.tool.error_code import CODES, gen
from rpc.tool.log_tool import logging_exception
from rpc.tool.protocol import PushUrlProtocol
from rpc.decorators import bind, bind_context
from rpc.decorators import list_interface
from rpc.cache import feedback_msg_cache
from rpc.exceptions import RPCIntegrityError

from gm_types.push import PUSH_INFO_TYPE


@bind_context('api/feedcategory/list')
def get_feed_category_list(ctx):
    feedcategorys = FeedbackCategory.objects.filter(enabled=True).order_by('position')
    result = []
    for fc in feedcategorys:
        result.append({
            'id': fc.id,
            'description': fc.description,
            'icon': fc.icon,
            'title': fc.title,
        })
    return result


@bind_context('api/feedbackcategory/get', login_required=True)
def get_feedback_categoty(ctx, id):
    user = get_user_from_context(ctx)
    user_extra = get_user_extra_by_user_id(user.id)
    fb_category = FeedbackCategory.objects.get(id=id)
    result = {}
    if fb_category:
        result['phone'] = user_extra.phone
        result['id'] = fb_category.id
        result['show_order_input'] = False
        if FEEDBACK_RELATED_OBJECT_TYPE.ORDER == fb_category.related_type:
            result['show_order_input'] = True
    return result


@bind_context('api/feedback/history', login_required=True)
@list_interface(offset_name='start_num', limit_name="count", element_model=Feedback)
def get_feedback_history(ctx, start_num=0, count=10):
    """
    :Function 反馈历史（列表）
    :param ctx:
    :return:
    """
    user = get_user_from_context(ctx)
    feedback = Feedback.objects.filter(user=user).order_by('-id')

    messages = []
    for fb in feedback[start_num:start_num+count]:
        redis_key = '{0}:{1}'.format(user.id, fb.id)

        ret = feedback_msg_cache.get(redis_key)

        if not ret:
            unread = False
        else:
            unread = True

        messages.append({
            "id": fb.id,
            "title": fb.feedbackcategory and fb.feedbackcategory.title or u'问题反馈',
            "content": escape(fb.content),
            "unread": unread
        })

    return messages


@bind_context('api/feedback/conversation_reply', login_required=True)
def conversation_reply(ctx, feedback_id, message_type, message):
    """
    :function 发送反馈回复
    :param ctx:
    :param start_num:
    :param limit:
    :return:
    """
    # validate messge_type
    if not message_type in (FEEDBACK_MESSAGE_TYPE.TXT, FEEDBACK_MESSAGE_TYPE.IMAGE):
        return gen(CODES.PARAMS_INCOMPLETE)

    user = get_user_from_context(ctx)
    try:
        feedback = Feedback.objects.get(id=feedback_id)
        if feedback.user != user:
            raise Feedback.DoesNotExist
    except Feedback.DoesNotExist:
        return gen(CODES.FEEDBACK_NOT_FOUND)

    message = escape(message)
    feedback_message = FeedbackMessage.objects.create(feedback=feedback,
                                                      person=user.person,
                                                      message_type=message_type,
                                                      message=message)
    feedback.has_more_asks = True
    feedback.save()
    return feedback_message.id


@bind_context('api/feedback/conversation_detail', login_required=True)
def get_conversation_detail(ctx, feedback_id, count=10):
    """
    :function 反馈详情对话列表接口, 返回最近的count条数据
    :param ctx:
    :return:
    """
    user = get_user_from_context(ctx)

    try:
        feedback = Feedback.objects.get(id=feedback_id)
        if feedback.user != user:
            raise Feedback.DoesNotExist
    except Feedback.DoesNotExist:
        return gen(CODES.FEEDBACK_NOT_FOUND)

    feedback_messages = FeedbackMessage.objects.filter(feedback=feedback)

    messages = []

    total = feedback_messages.count()
    count = min(total, count)

    for msg in feedback_messages[total-count:]:
        portait = uid = None

        try:
            uid = msg.servant.user.id
            portrait = get_full_path(settings.GENGMEI_CUSTOMER_SERVICES_PORTRAIT)
        except:
            pass

        if not uid:
            uid = msg.person.user.id
            ue = get_user_extra_by_user_id(uid)
            portrait = get_full_path(ue.portrait) or get_full_path(u'img%2Fuser_portrait.png')

        messages.append({
                'portrait': portrait,
                'uid': uid,
                'message': escape(msg.message),
                'message_type': msg.message_type,
                'created_time': get_timestamp_or_none(msg.created_time)
        })

    order_id, order_name = '', ''

    if feedback.related_id:
        if feedback.feedbackcategory.related_type == FEEDBACK_RELATED_OBJECT_TYPE.ORDER:
            try:
                order = Order.objects.get(pk=feedback.related_id)
                order_id = feedback.related_id
                service_snapshot = json.loads(order.service_snapshot)
                order_name = service_snapshot['name']
            except:
                logging_exception()

    images = [ret.image_url for ret in feedback.images.all() if ret]

    feedback_content = feedback.content and feedback.content.strip() or ''
    ue = get_user_extra_by_user_id(feedback.user.id)
    result = {
        'feedback': {
            'id': feedback.id,
            'content': escape(feedback_content),
            'order_id': order_id,
            'order_name': order_name,
            'images': images,
            'uid': feedback.user.id,
            'portrait': get_full_path(ue.portrait) or get_full_path(u'img%2Fuser_portrait.png'),
            'created_time': get_timestamp_or_none(feedback.created_time),
        },
        'messages': messages
    }

    redis_key = '{0}:{1}'.format(user.id,feedback_id)
    feedback_msg_cache.delete(redis_key)
    return result


@bind_context('api/feedback/create', login_required=True)
def feedback_create(ctx, id, content, phone=None, qq=None, images=[], relate_id=None):
    """
    :Function 递交反馈信息
    :param ctx:
    :param id:
    :param content:
    :param phone:
    :param qq:
    :param images:
    :param relate_id:
    :return:
    """
    user = get_user_from_context(ctx)
    feedbackcategory =FeedbackCategory.objects.get(id=id)
    feedback = Feedback()

    feedback.user = user
    feedback.feedbackcategory = feedbackcategory

    if content:
        content = escape(content)
        feedback.content = content

    if phone:
        feedback.phone = phone

    if qq:
        feedback.qq = qq

    if relate_id:
        feedback.related_id = relate_id

    redis_key = 'create_check:{0}'.format(user.id) # redis_key 缓存用户反馈
    ret = feedback_msg_cache.get(redis_key)

    task_info = {
        'user_id':user.id,
        'content':content,
        'phone':phone,
        'qq':qq,
        'relate_id':relate_id,
    }
    if ret:
        ret = json.loads(ret)
        if ret == task_info:
            return gen(CODES.FEEDBACK_REPETITION)

    feedback_msg_cache.setex(redis_key,6,json.dumps(task_info))# expire in 6s

    feedback.save()

    for image in images:
        fb_image = FeedbackImage()
        fb_image.feedback = feedback
        fb_image.image_url = image
        fb_image.save()

    return {'feedback_id': feedback.id}


@bind_context('api/feedback/reply_status', login_required=True)
def conversation_reply_status(ctx, feedback_id):
    """NOTE: this api is only used internally
    :Function 添加一个这个反馈是否已经被客服回复过
    :param ctx:
    :param feedback_id:
    :return:
    """
    try:
        feedback = Feedback.objects.get(id=feedback_id)
    except Feedback.DoesNotExist:
        return gen(CODES.FEEDBACK_NOT_FOUND)

    # set reply status flag
    redis_key = '{0}:{1}'.format(feedback.user.id, feedback_id)
    ret = feedback_msg_cache.set(redis_key, 1)

    return gen(CODES.SUCCESS)

@bind_context('api/feedback/category/get_by_title', login_required=False)
def get_feedback_category_by_title(ctx, title):

    try:
        feedback = FeedbackCategory.objects.get(title=title)
    except FeedbackCategory.DoesNotExist:
        return gen(CODES.FEEDBACK_NOT_FOUND)

    result = {
        'id': feedback.id,
        'title': feedback.title,
    }
    return result


@bind_context('api/user/feedback/create')
def add_face_skin_feedback(ctx, device_id, function, question_answer):
    for qa in question_answer:
        function_feedback = FunctionFeedback()
        function_feedback.device_id = device_id
        function_feedback.function = function
        function_feedback.question = qa.get("question", "")
        function_feedback.rank = qa.get("rank", 0)
        function_feedback.answer = qa.get("answer", "")
        function_feedback.save()
    return gen(CODES.SUCCESS)


@bind_context('api/feedback/questions/answers')
def question_feedback_questions_answers(ctx, function):
    questions = FeedbackQuestion.objects.filter(is_online=1, function=function)
    question_ids = [q.id for q in questions]
    answers = FeedbackAnswer.objects.filter(is_online=1, question_id__in=question_ids)
    question_id2answers = dict()
    for answer in answers:
        new_answer = dict()
        new_answer['answer_id'] = answer.id
        new_answer['answer_content'] = answer.content
        question_id2answers.setdefault(answer.question_id, []).append(new_answer)

    result = list()
    for question in questions:
        qa = dict()
        qa['question_id'] = question.id
        qa['question_title'] = question.title
        qa['question_mold'] = question.mold
        qa['question_rank'] = question.rank
        qa_answers = question_id2answers.get(question.id, [])
        qa_answers.sort(key=lambda x: x['answer_id'])
        qa['question_answers'] = qa_answers
        result.append(qa)
    result.sort(key=lambda x: x['question_id'])
    return {"questions_and_answers": result}


@bind_context('api/feedback/times')
def recording_user_visited(ctx, device_id, function):
    result = dict(period=0)
    record = UserVisitRecord.objects.filter(device_id=device_id, function=function).first()
    if not record:
        record = UserVisitRecord()
        record.device_id = device_id
        record.function = function
        record.visit_times = 0
        record.submit_times = 0
        record.last_visit_time = datetime.now()
    record.visit_times += 1
    result['visit_times'] = record.visit_times
    result['submit_times'] = record.submit_times
    result['timedelta'] = (datetime.now() - record.last_visit_time).days
    record.save()

    function_period = FeedbackFunctionPeriod.objects.filter(function=function).first()
    if function_period:
        result['period'] = function_period.period

    return result


@bind_context('api/feedback/submit')
def submit_user_feedback(ctx, device_id, function, question_answers):
    record = UserVisitRecord.objects.filter(device_id=device_id, function=function).first()
    record.submit_times += 1
    record.save()
    for question_answer in question_answers:
        submit = FeedbackUserSubmit.objects.filter(
            device_id=device_id,
            question_id=question_answer['question_id']).first()
        if not submit:
            submit = FeedbackUserSubmit()
            submit.question_id = question_answer['question_id']
            submit.device_id = device_id
        submit.answer_ids = ','.join([str(aid) for aid in question_answer['answer_ids']])
        submit.save()
    return gen(CODES.SUCCESS)


@bind_context('api/user_feedback_answer')
def user_feedback_answer(ctx, device_id, function, title):

    question_obj = FeedbackQuestion.objects.filter(function=function, title=title, is_online=True).last()
    if not question_obj:
        return []

    submit_obj = FeedbackUserSubmit.objects.filter(device_id=device_id, question_id=question_obj, is_online=True).last()
    if not submit_obj:
        return []

    answer_ids = submit_obj.answer_ids.split(',')
    answers = FeedbackAnswer.objects.filter(id__in=answer_ids).all()

    return [{"id": item.id, "content": item.content} for item in answers]
