# coding=utf-8

from django.db import transaction
from gm_types.user_hierarchy import EventType

from rpc.decorators import bind_context, bind
from rpc.tool.error_code import CODES, gen
from rpc.cache import code_cache
from rpc.tool.random_tool import random_str

from api.tool.verification_code import VerifiedCode
from api.models import Person
from api.tool.sms_tool import send_verified_code, send_person_code
from api.tool.user_tool import get_user_from_context
from api.tool.verification_code import verify_phone_code
from api.models import VERIFY_CODE_TYPE
from services.custom_phone_service import PhoneService

from utils.phone import format_phone
from mimas.tasks import send_event_task


@bind('api/phone/400_host_number')
def get_current_400_host_number():
    return {'host_num': PhoneService.get_host_num()}


@bind("api/phone/code")
def phone_code(phone, code_type=VERIFY_CODE_TYPE.CREATE):
    if code_type not in [VERIFY_CODE_TYPE.CREATE,
                         VERIFY_CODE_TYPE.LOGIN,
                         VERIFY_CODE_TYPE.UPDATE_PHONE,
                         VERIFY_CODE_TYPE.REGIN]:
        return gen(CODES.OPERATION_NOT_SUPPORTED)

    phone = format_phone(phone)
    try:
        Person.objects.get(phone=phone)
        if code_type == VERIFY_CODE_TYPE.CREATE:
            return gen(CODES.PERSON_EXIST)

    except Person.DoesNotExist:
        if code_type == VERIFY_CODE_TYPE.LOGIN:
            return gen(CODES.PERSON_NOT_FOUND)

    send_verified_code(phone, code_type)
    return gen(CODES.SUCCESS)


@bind_context("api/phone/bind_code", login_required=True)
def bind_phone_code(ctx, phone):
    user = get_user_from_context(ctx)
    phone = format_phone(phone)
    try:
        Person.objects.get(phone=phone)
        return gen(CODES.BIND_EXIST_PHONE)
    except Person.DoesNotExist:
        send_person_code(phone, user.person, VERIFY_CODE_TYPE.BIND)
        return gen(CODES.SUCCESS)


@bind_context("api/phone/update_code", login_required=True)
def bind_phone_update_code(ctx, phone):
    user = get_user_from_context(ctx)
    phone = format_phone(phone)
    try:
        person = Person.objects.get(phone=phone)
        if person.id == user.person.id:
            send_person_code(phone, user.person, VERIFY_CODE_TYPE.UPDATE)
            return gen(CODES.SUCCESS)
        else:
            return gen(CODES.NO_PERMISSION)
    except Person.DoesNotExist:
        return gen(CODES.PERSON_NOT_FOUND)


@bind("api/verified/code")
def verified_code(phone, code, code_type=VERIFY_CODE_TYPE.USER_AUTHENTICATION):
    """校验验证码"""

    phone = format_phone(phone)
    if not (phone and code):
        return  gen(CODES.PARAMS_INCOMPLETE)

    return VerifiedCode.verify(code, phone=phone, code_type=code_type)


@bind_context("api/phone/bind", login_required=True)
def phone_bind(ctx, phone, code):
    user = get_user_from_context(ctx)
    phone = format_phone(phone)
    key = "phone:%d:%s:%s" % (VERIFY_CODE_TYPE.BIND, user.person.id.hex, phone)
    verified_code = code_cache.get(key)
    if verified_code is None or verified_code != code:
        return gen(CODES.INVALID_CODE)

    try:
        Person.objects.get(phone=phone)
        return gen(CODES.BIND_EXIST_PHONE)

    except Person.DoesNotExist:
        with transaction.atomic():
            u = user._get_full_field_content_('username')
            if u.isdigit() and u == user.person.phone:
                un = u
                user.username = '%s_phone_%s' % (un, random_str(8))

            user.person.phone = phone
            user.userextra.phone = phone
            user.userextra.save()
            user.save()
            user.person.save()

        event_data = send_event_task(user_id=user.id, event_type=EventType.BINDPHONE)
        growth_value, point_value = event_data['growth_value'], event_data['point_value']
        submit_count = event_data['submit_count']

    return {'growth_value': growth_value, 'point_value': point_value, 'submit_count': submit_count}


@bind_context("api/phone/code/verify", login_required=True)
def phone_code_verify(ctx, phone, code,
                      verify_code_type=VERIFY_CODE_TYPE.UPDATE_PHONE):
    # 用于m站更新手机号
    get_user_from_context(ctx)
    phone = format_phone(phone)
    if verify_code_type is None:
        return False
    result = verify_phone_code(phone, code, code_type=verify_code_type)
    return result


@bind("api/phone/change", login_required=True)
def phone_change(phone, code_type=VERIFY_CODE_TYPE.CHANGE_PHONE_NUMBER):
    phone = format_phone(phone)
    send_verified_code(phone, code_type)
    return gen(CODES.SUCCESS)


@bind_context("api/phone/change/verify", login_required=True)
def phone_change_verify(ctx, phone, code, verify_code_type=VERIFY_CODE_TYPE.CHANGE_PHONE_NUMBER):
    phone = format_phone(phone)
    result = verify_phone_code(phone, code, code_type=verify_code_type)
    return result


@bind("api/phone/yd_apply")
def youngdoctor_apply_code(phone):
    if not phone:
        return
    phone = format_phone(phone)
    code_type = VERIFY_CODE_TYPE.ACTIVITY_APPLY
    send_verified_code(phone, code_type)
    return gen(CODES.SUCCESS)


@bind('api/phone/share/send')
def send_phone_share_code(phone):
    """
    11.11大促临时代码
    :param phone:
    :return:
    """
    phone = format_phone(phone)
    try:
        Person.objects.get(phone=phone)
        return gen(CODES.PERSON_EXIST)
    except Person.DoesNotExist:
        send_verified_code(phone, code_type=VERIFY_CODE_TYPE.CREATE)
        return gen(CODES.SUCCESS)


@bind_context('api/phone/user_authenticate_check', login_required=True)
def user_authenticate_check(ctx, phone, code_type=VERIFY_CODE_TYPE.USER_AUTHENTICATION):
    phone = format_phone(phone)
    send_verified_code(phone, code_type)
    return gen(CODES.SUCCESS)


@bind_context("api/phone/user_bind_judge")
def user_phone_bind_judge(ctx):
    """
    用户绑定手机号逻辑判断。
    :param ctx:
    :return:
    """
    user = get_user_from_context(ctx)
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    person = Person.get_or_create(user)

    result = {
        "need_bind": True
    }
    if person and person.phone:
        result["need_bind"] = False
    
    return result
