# coding=utf-8
from __future__ import unicode_literals

import base64
import datetime
import json
import logging
import re
import six
from hashlib import md5

import requests
from django.conf import settings

from rpc.cache import code_cache
from rpc.cache import send_cache
from rpc.tool.log_tool import logging_exception
from rpc.tool.random_tool import random_str
from rpc.tool.error_code import CODES, gen
from api.tool.verification_code import (
    get_verification_message,
    VerifiedCode
)
from api.tool.datetime_tool import get_seconds_left_to_end_of_day
from sms.utils.smsfactory import send_sms as send_sms_v2
from gm_types.user_communication.sms.enum import PlatformDirective
from gm_types.gaia import PHONE_AREA_CODE

__author__ = 'leaf'


def getSig(Sid, Token, timestamp):
    """
    返回签名
    :param Sid:
    :param Token:
    :param timestamp:
    :return:
    """
    sig = Sid + Token + timestamp
    return md5(sig).hexdigest().upper()


def getAuth(Sid, timestamp):
    """
    生成授权信息
    :param Sid:
    :param timestamp:
    :return:
    """
    src = Sid + ":" + timestamp
    return base64.encodestring(src).strip()


def is_plus_phone_num(cellphone_num):
    """
        判断是否手机号码，包含国家
    """
    regex = re.compile('^\+?\d{6,}$')
    return regex.match(cellphone_num)


def is_cellphone_num(cellphone_num):
    """
        判断是否手机号码
    """
    regex = re.compile('^1\d{10}$')
    return regex.match(cellphone_num)


def _send_sms_md(phone, msg):
    """
    漫道短信通道
    """
    data = {u'sn': u'SDK-BBX-010-19243',
            u'pwd': u'E5D3CF92329CA75E6B794ADE37154616',
            u'mobile': phone,
            u'content': msg.encode(u'gbk'),
            u'ext': u'',
            u'stime': u'',
            u'rrid': u''}
    requests.post(
        u'http://sdk.entinfo.cn:8060/webservice.asmx/mt', data)
    logging.info(
        "sms platform [md], phone is: {}, msg is: {}".format(phone, msg))
    return 0


def _send_sms_ucpaas(phone, temp_id, params):
    """
    云之讯
    :param phone:
    :param temp_id:
    :param params:
    :return:
    """
    nowdate = datetime.datetime.now()
    timestamp = nowdate.strftime("%Y%m%d%H%M%S")
    sig = getSig(settings.UCPAAS_SID, settings.UCPAAS_TOKEN, timestamp)

    # 验证码短信频率
    if _check_sms_ucpaas(phone, temp_id) is False:
        return 0

    url = "{}:{}/{}/Accounts/{}/Messages/templateSMS?sig={}" \
        .format(settings.UCPAAS_SERVER_HOST, settings.UCPAAS_SERVER_PORT, settings.UCPAAS_VERSION,
                settings.UCPAAS_SID, sig)

    # 生成auth
    auth = getAuth(settings.UCPAAS_SID, timestamp)

    payload = {"templateSMS": {"appId": settings.UCPAAS_APPID, "param": params, "templateId": temp_id,
                               "to": phone}}

    headers = {"Accept": "application/json", "Content-Type": "application/json;charset=utf-8",
               "Content-Length": len(payload), "Authorization": auth}

    r = requests.post(url, headers=headers, data=json.dumps(payload))
    data = r.text
    locations = json.loads(data)
    logging.info(locations)
    logging.info("sms platform [ucpaas], phone is: {}, temp_id is: {}, params is: {}".format(
        phone, temp_id, params))
    return 0


def _send_email_for_test(phone, content):
    try:
        email_list = settings.TEST_EMAIL_LIST
    except AttributeError:
        email_list = []

    try:
        phone_email_map = settings.TEST_PHONE_EMAIL_MAP
    except AttributeError:
        phone_email_map = {}

    target_email_list = list(email_list)

    email_for_phone = phone_email_map.get(phone)
    if email_for_phone:
        if isinstance(email_for_phone, six.string_types):
            target_email_list.append(email_for_phone)
        elif isinstance(email_for_phone, list):
            target_email_list.extend(email_for_phone)
        else:
            raise TypeError('unexpected type in TEST_PHONE_EMAIL_MAP: {}'.format(
                type(email_for_phone).__name__))

    if not target_email_list:
        return

    subject = u'[开发测试]短信 to {}'.format(phone)

    from rpc.tool.internal_email_tool import send_internal_email
    send_internal_email(
        target_email_list,
        subject=subject,
        content=content,
    )


def _check_sms_ucpaas(phone, temp_id):
    if temp_id and int(temp_id) != 10862:
        return True

    sdt_key = "send_times:%s:%s" % (phone, datetime.datetime.today().strftime('%y%m%d'))
    send_times = send_cache.get(sdt_key)
    max_times = settings.UCPASS_DAILY_LIMIT

    if send_times and int(send_times) < max_times:
        send_cache.incr(sdt_key)

    elif send_times and int(send_times) >= max_times:
        logging.error(
            u"[sms_service.send_sms] SENDDING TIMES LIMITTED, phone number:%s" % phone)
        return gen(CODES.SENT_TOO_MANY_VERIFICATION_CODE)

    elif not send_times:
        send_cache.setex(sdt_key, get_seconds_left_to_end_of_day(), 1)

    sd_key = "send:%s" % (phone)
    send = send_cache.get(sd_key)
    if send is None:
        send_cache.setex(sd_key, 60, 1)

    else:
        logging.error(
            u"[sms_service.send_sms] SENDDING FREQUENCY LIMITTED, phone number:%s" % phone)
        return False

    return True


def send_sms(phone, msg, temp_id, params, is_debug=False, channel=None):
    """
    已废弃

    发送短信函数
    :param phone: 手机号码
    :param msg: 短信内容
    :param temp_id: 云之讯模版ID
    :param params: 云之讯参数
    :param is_debug: 调试模式
    :return:
    """

    try:
        raise Exception("function deprecated")
    except Exception:
        logging_exception()

    if not is_cellphone_num(phone):
        logging.error(u"[sms_service.send_sms] INVALID phone number: %s", phone)
        return False

    if params:
        if u'】' in params:
            params = params.replace(u'】', ']')

        if u'【' in params:
            params = params.replace(u'【', '[')

    def _send_sms():
        # check sms daily limit
        k = "daily_limit:%s:%s" % (phone, datetime.datetime.today().strftime('%y%m%d'))
        c = send_cache.get(k)
        if not c:
            send_cache.setex(k, get_seconds_left_to_end_of_day(), 0)
            c = 0

        if c and int(c) >= settings.SMS_DAILY_LIMIT:
            logging.info(u"sms reached daily limit: %s", phone)
            return False

        send_cache.incr(k)

        if channel is None:
            if settings.SMS_MODEL == 'ucpaas':
                _send_sms_ucpaas(phone, temp_id, params)
            else:
                _send_sms_md(phone, msg)

        elif channel == 'ucpass':
            _send_sms_ucpaas(phone, temp_id, params)

        elif channel == 'md':
            _send_sms_md(phone, msg)

        else:
            logging.error(u"[sms_service.send_sms] unsupport sms channel")

    if settings.DEBUG or is_debug:
        if phone in settings.TEST_PHONE_LIST:
            _send_sms()

        else:
            logging.info(u"debug model, phone number doesn't in test phone list: %s", phone)

        _send_email_for_test(phone, msg)
        return

    _send_sms()


def get_smart_template_and_platform_id(phone):
    paltform_map = {
        PHONE_AREA_CODE.TAIWAN: (38, PlatformDirective.YUNPIAN),
        PHONE_AREA_CODE.HONGKONG: (38, PlatformDirective.YUNPIAN),
        PHONE_AREA_CODE.JAPAN: (39, PlatformDirective.YUNPIAN),
        PHONE_AREA_CODE.KOREA: (39, PlatformDirective.YUNPIAN),
        PHONE_AREA_CODE.THAILAND: (39, PlatformDirective.YUNPIAN),
    }
    for key, value in paltform_map.iteritems():
        if phone.startswith(key):
            return value
    return 43, settings.DEFAULT_SMS_PLATFORM


def code_times_limit(phone):
    sdt_key = "send_times:%s:%s" % (phone, datetime.datetime.today().strftime('%y%m%d'))
    send_times = send_cache.get(sdt_key)
    max_times = settings.SMS_DAILY_LIMIT
    if send_times is None:
        send_cache.setex(sdt_key, get_seconds_left_to_end_of_day(), 0)

    elif int(send_times) < max_times:
        send_cache.incr(sdt_key)

    elif int(send_times) >= max_times:
        logging.error(
            u"[sms_service.send_sms] SENDDING TIMES LIMITTED, phone number:%s" % phone)
        return gen(CODES.SENT_TOO_MANY_VERIFICATION_CODE)


def send_verified_code(phone, code_type):
    code = VerifiedCode.generate(phone, code_type)
    logging.info(u"{} verification code is {}, type is {}".format(phone, code, code_type))
    template_id, platform = get_smart_template_and_platform_id(phone)
    code_times_limit(phone)
    send_sms_v2(phone, template_id, [{u'code': code}, {'product': '更美APP'}], platform=platform)
    return code


def send_person_code(phone, person, code_type, exists_user=True):
    key = "phone:%d:%s:%s" % (code_type,
                              person.id.hex if exists_user else None,
                              phone)
    code = code_cache.get(key)
    if code is None:
        code = random_str(4, digit=True)
    code_cache.setex(key, 15 * 60, code)
    code = int(code)
    logging.info(u"{} verification code is {}, type is {}".format(
        phone, get_verification_message(code), code_type))
    template_id, platform = get_smart_template_and_platform_id(phone)
    code_times_limit(phone)
    send_sms_v2(phone, template_id, [{u'code': get_verification_message(code)}, {'product': '更美APP'}],
                platform=platform)
    return code


def send_vericode(phone, code):
    """发送验证码短信
    """
    logging.info(u"{} verification code is {}".format(phone, code))
    template_id, platform = get_smart_template_and_platform_id(phone)
    code_times_limit(phone)
    send_sms_v2(phone, template_id, [{u'code': code}, {'product': '更美APP'}], platform=platform)
