# -*- coding: utf8 -*-
from __future__ import absolute_import
import base64
import requests
import datetime
import json
import hashlib
import urllib
import time
from hashlib import md5
from django.conf import settings
from .dict_tool import ListDict
from rpc.cache import send_cache
from rpc.tool.error_code import gen, CODES
from rpc.tool.log_tool import sms_logger
from api.tool.datetime_tool import get_seconds_left_to_end_of_day
from .exception import SendTimeLimit, TemplateNotFound


class SMSPlatform:
    template = True
    max_phones = 200

    def __init__(self, *args, **kwargs):
        pass

    def send(self, phone, template_id, params, msg):
        if self.template and not template_id:
            raise TemplateNotFound
        l = len(phone)
        for i in range(l / self.max_phones + 1 if l % self.max_phones else l / self.max_phones):
            phone_str = ','.join(phone[i * self.max_phones: (i + 1) * self.max_phones])
            ret = self._send(phone_str, template_id, params, msg)
            self.log(phone_str, template_id, params, ret)

    def _send(self, phone, template_id, params, msg):
        raise NotImplementedError

    def log(self, phone, template_id, params, ret):
        platform = self.__class__.__name__.lower()
        kwargs = {
            u'platform': platform,
            u'phone': phone,
            u'template_id': template_id,
            u'response': ret,
            u'params': params,
        }
        sms_logger.info(json.dumps(kwargs, indent=2))


class UCPaas(SMSPlatform):
    def __init__(self, host=settings.UCPAAS_SERVER_HOST, port=settings.UCPAAS_SERVER_PORT, token=settings.UCPAAS_TOKEN,
                 sid=settings.UCPAAS_SID, version=settings.UCPAAS_VERSION, app_id=settings.UCPAAS_APPID,
                 daily_limit=settings.UCPASS_DAILY_LIMIT):
        self.host = host
        self.port = port
        self.token = token
        self.sid = sid
        self.version = version
        self.app_id = app_id
        self.daily_limit = daily_limit

    def _send(self, phone, template_id, params, msg):
        self.check_sms_ucpaas(phone, template_id)
        params = ListDict(params).to_str()
        if params:
            if u'】' in params:
                params = params.replace(u'】', ']')

            if u'【' in params:
                params = params.replace(u'【', '[')
        nowdate = datetime.datetime.now()
        timestamp = nowdate.strftime("%Y%m%d%H%M%S")
        sig = self.getSig(timestamp)

        url = "{}:{}/{}/Accounts/{}/Messages/templateSMS?sig={}" \
            .format(self.host, self.port, self.version,
                    self.sid, sig)

        # 生成auth
        auth = self.getAuth(timestamp)

        payload = {"templateSMS": {"appId": self.app_id, "param": params, "templateId": template_id,
                                   "to": phone}}

        headers = {"Accept": "application/json", "Content-Type": "application/json;charset=utf-8",
                   "Content-Length": len(payload), "Authorization": auth}
        res = requests.post(url, headers=headers, data=json.dumps(payload))
        res.raise_for_status()
        ret = res.text
        return ret

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

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

    def check_sms_ucpaas(self, phone, temp_id):
        if temp_id and int(temp_id) != 10862:
            return True
        phone = phone.split(',')

        def check(number):
            sdt_key = "send_times:{}:{}".format(number, datetime.datetime.today().strftime('%y%m%d'))
            send_times = send_cache.get(sdt_key)
            max_times = self.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:
                raise SendTimeLimit

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

            sd_key = "send:{}".format(number)
            send = send_cache.get(sd_key)
            if send is None:
                send_cache.setex(sd_key, 60, 1)
            else:
                raise SendTimeLimit

        for p in phone:
            check(p)


class ALiDayu(SMSPlatform):
    def __init__(self, host=settings.ALIDAYU_HOST, app_key=settings.ALIDAYU_APPKEY, secret=settings.ALIDAYU_SECRET,
                 sign_name=settings.ALIDAYU_SIGNNAME):
        self.host = host
        self.app_key = app_key
        self.secret = secret
        self.sign_name = sign_name

    def sign(self, parameters):
        # ===========================================================================
        # '''签名方法
        # @param secret: 签名需要的密钥
        # @param parameters: 支持字典和string两种
        # '''`
        # ===========================================================================
        # 如果parameters 是字典类的话
        if hasattr(parameters, "items"):
            keys = parameters.keys()
            keys.sort()
            parameters = "%s%s%s" % (str(self.secret),
                                     str().join('%s%s' % (str(key), str(parameters[key])) for key in keys),
                                     str(self.secret))
        sign = hashlib.md5(parameters).hexdigest().upper()
        return sign

    def get_url(self, params):
        sys_parameters = {
            'format': 'json',
            'app_key': self.app_key,
            'sign_method': "md5",
            'v': '2.0',
            'timestamp': str(long(time.time() * 1000)),
            'method': 'alibaba.aliqin.fc.sms.num.send',
        }
        sys = sys_parameters.copy()
        sys.update(params)
        sys_parameters['sign'] = self.sign(sys)
        return self.host + "?" + urllib.urlencode(sys_parameters)

    def _send(self, phone, template_id, params, msg):
        params = ListDict(params).to_dict_str()
        data = {
            'extend': '123456',
            'rec_num': phone,
            'sms_free_sign_name': self.sign_name.encode('utf-8'),
            'sms_param': json.dumps(params),
            'sms_template_code': template_id,
            'sms_type': 'normal'
        }
        url = self.get_url(data)
        res = requests.post(url, data=data)
        res.raise_for_status()
        return res.text


class Md(SMSPlatform):
    template = False

    def __init__(self, host=settings.MD_HOST, sn=settings.MD_SN,
                 pwd=settings.MD_PWD):
        self.host = host
        self.sn = sn
        self.pwd = pwd

    def _send(self, phone, template_id, params, msg):
        """
        漫道短信通道
        """
        msg = u'【更美APP】' + msg
        data = {u'sn': self.sn,
                u'pwd': self.pwd,
                u'mobile': phone,
                u'content': msg.encode(u'gbk'),
                u'ext': u'',
                u'stime': u'',
                u'rrid': u''}
        res = requests.post(
            self.host, data)
        ret = res.text
        return ret


class YunPian(SMSPlatform):
    # 主要发国际短信 每次发送一条
    max_phones = 1
    template = False

    def __init__(self, apikey=settings.YUNPIAN_API_KEY, host=settings.YUNPIAN_HOST):
        self.apikey = apikey
        self.host = host

    def _send(self, phone, template_id, params, msg):
        data = urllib.urlencode({'apikey': self.apikey, 'text': msg.encode(u'utf-8'), 'mobile': phone})
        url = self.host + '/v2/sms/single_send.json'
        res = requests.post(url, data=data)
        res.raise_for_status()
        return res.text
