import base64
import hashlib
import time
import uuid

import requests

from collections import OrderedDict

from django.conf import settings
from common.exceptions import JMSException
from common.utils import get_logger

from .base import BaseSMSClient

logger = get_logger(__file__)


class HuaweiClient:
    def __init__(self, app_key, app_secret, url, sign_channel_num):
        self.url = url[:-1] if url.endswith('/') else url
        self.app_key = app_key
        self.app_secret = app_secret
        self.sign_channel_num = sign_channel_num

    def build_wsse_header(self):
        now = time.strftime('%Y-%m-%dT%H:%M:%SZ')
        nonce = str(uuid.uuid4()).replace('-', '')
        digest = hashlib.sha256((nonce + now + self.app_secret).encode()).hexdigest()
        digestBase64 = base64.b64encode(digest.encode()).decode()
        formatter = 'UsernameToken Username="{}",PasswordDigest="{}",Nonce="{}",Created="{}"'
        return formatter.format(self.app_key, digestBase64, nonce, now)

    def send_sms(self, receiver, signature, template_id, template_param):
        sms_url = '%s/%s' % (self.url, 'sms/batchSendSms/v1')
        headers = {
            'Authorization': 'WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
            'X-WSSE': self.build_wsse_header()
        }
        body = {
            'from': self.sign_channel_num, 'to': receiver, 'templateId': template_id,
            'templateParas': template_param, 'signature': signature
        }
        try:
            response = requests.post(sms_url, headers=headers, data=body)
            msg = response.json()
        except Exception as error:
            raise JMSException(code='response_bad', detail=error)
        return msg


class HuaweiSMS(BaseSMSClient):
    SIGN_AND_TMPL_SETTING_FIELD_PREFIX = 'HUAWEI'

    @classmethod
    def new_from_settings(cls):
        return cls(
            app_key=settings.HUAWEI_APP_KEY,
            app_secret=settings.HUAWEI_APP_SECRET,
            url=settings.HUAWEI_SMS_ENDPOINT,
            sign_channel_num=settings.HUAWEI_SIGN_CHANNEL_NUM
        )

    def __init__(self, app_key: str, app_secret: str, url: str, sign_channel_num: str):
        self.client = HuaweiClient(app_key, app_secret, url, sign_channel_num)

    def send_sms(
            self, phone_numbers: list, sign_name: str, template_code: str,
            template_param: OrderedDict, **kwargs
    ):
        phone_numbers_str = ','.join(phone_numbers)
        template_param = '["%s"]' % template_param.get('code')
        req_params = {
            'receiver': phone_numbers_str, 'signature': sign_name,
            'template_id': template_code, 'template_param': template_param
        }
        try:
            logger.info(f'Huawei sms send: '
                        f'phone_numbers={phone_numbers} '
                        f'sign_name={sign_name} '
                        f'template_code={template_code} '
                        f'template_param={template_param}')

            resp_msg = self.client.send_sms(**req_params)

        except Exception as error:
            raise JMSException(code='response_bad', detail=error)

        resp_code = resp_msg.get('code', '')
        resp_desc = resp_msg.get('description', '')
        if resp_code != '000000':
            raise JMSException(code='response_bad',
                               detail="{}:{},{}:{}".format("code", resp_code, "description", resp_desc))
        return resp_msg


client = HuaweiSMS