# coding=utf-8
from __future__ import absolute_import, unicode_literals, print_function

import time
import urllib
import urllib2
import datetime
import urlparse
from hashlib import md5
import json
import requests
from django.conf import settings

from gm_types.gaia import (
    PROMOTION_CHANNEL_NAME,
    CHANNEL_CALLBACK_TYPE,
    CLIENT_TYPE,
    CHANNEL_STATUS,
    PLATFORM_CHANNEL
)

from api.util import auth_util
from statistic.tasks import delayed_activate_callback
from rpc.decorators import bind
from rpc.tool.log_tool import channel_logger, logging_exception
from ..models import PromotionChannel, Device, SheQuDevice
from ..utils.guangdiantong import guangdiantong_active,get_token

# 请求时校验ssl
_VERIFIED = False

def _form_google_user_agent(app_name, app_version, platform, os_version, device_model, build_number=''):
    if not all([app_name, app_version, platform, os_version, device_model]):
        return ''

    platform = 'Android' if platform.lower() == "android" else 'IOS'
    build = build_number if build_number else '13D15'
    name = app_name
    version = app_version
    os_and_version = '{} {}'.format(platform, os_version)
    device = device_model
    build = 'Build/{}'.format(build)
    result = '{}: {}/{} ({}; {}; {}; Proxy)'.format(platform, name, version, os_and_version, device, build)

    return result


def _google_channel_activate(idfa, app_name=None, app_version=None, platform=None, os_version=None,
                             device_model=None, uuid=None, client_ip=None, build_number=None):
    if not all([idfa, app_name, app_version, platform, os_version, device_model]):
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_INVALID_PARAMS}
    if platform.lower() == "android":
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    params_user_agent = {
        'app_name': app_name,
        'app_version': app_version,
        'platform': platform,
        'os_version': os_version,
        'device_model': device_model,
        'build_number': build_number,
    }
    user_agent = _form_google_user_agent(**params_user_agent)
    if not user_agent:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    params_request = {
        'dev_token': settings.DEV_TOKEN,
        'link_id': settings.LINK_ID,
        'app_event_type': 'first_open',
        'rdid': uuid,
        'id_type': 'idfa',
        'lat': 0,
        'app_version': app_version,
        'os_version': os_version,
        'sdk_version': app_version,
        'timestamp': time.time(),
    }
    params_header = {
        'User-Agent': user_agent,
        'X-Forwarded-For': client_ip,
        'Content-Length': 0,
    }

    res = requests.post(url=settings.GOOGLE_CHANNEL_URL, headers=params_header, params=params_request)
    if res.status_code != 200:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json and not res_json.get('attributed'):
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_NO_PROMOTION}

    time_now = datetime.datetime.now()
    params = {
        'idfa': idfa,
        'appid': PROMOTION_CHANNEL_NAME.GOOGLE,
        'update_time': time_now,
        'active_time': time_now,
        'callback_type': CHANNEL_CALLBACK_TYPE.POST_CALLBACK,
        'callback': res.url,
        'callback_response': res.text,
        'client_type': CLIENT_TYPE.USER,
        'platform_type': PLATFORM_CHANNEL.IOS
    }
    try:
        PromotionChannel.objects.create(**params)
        result = {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}
    except Exception as e:
        record_msg = 'google-activate-exception: %s, %s' % (e.message, params)
        channel_logger.error(record_msg)
        result = {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    return result


def _baidu_channel_activate(record):

    if not record.callback:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    callback = record.callback
    callback = callback.replace('{{ATYPE}}', 'activate')
    callback = callback.replace('{{AVALUE}}', '0')
    sign = md5(callback + settings.BAIDU_AKEY).hexdigest()

    res = requests.get(callback, params={'sign': sign})
    if res.status_code != 200:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json and res_json['error_code'] != 0:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_NO_PROMOTION}

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    record.callback_response = res.text if res.text else ''
    record.save(update_fields=['active_time', 'update_time', 'callback_response'])

    return {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}


def _baidushouzhu_channel_activate(record):

    if not record.callback:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    packagename = "com.wanmeizhensuo.zhensuo"
    if not record.idfa and record.platform_type == PLATFORM_CHANNEL.UNKNOWN:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    app_type = 'android' if record.platform_type == PLATFORM_CHANNEL.ANDROID else 'ios'
    now_time = int(time.time())

    k_str = "activetime={activetime}apptype={app_type}clickid={clickid}packagename={packagename}".format(
        app_type=app_type, activetime=now_time, clickid=record.idfa, packagename=packagename
    )
    k = md5(k_str + settings.BAIDU_SHOUZHU).hexdigest()

    res = requests.get(record.callback, params={'activetime': now_time, 'apptype': app_type, 'clickid': record.idfa,
                                                 'k': k, 'packagename': packagename})
    if res.status_code != 0:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json and res_json['error_code'] != 0:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_NO_PROMOTION}

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    record.callback_response = res.text if res.text else ''
    record.save(update_fields=['active_time', 'update_time', 'callback_response'])

    return {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}


def _mobilebaidu_channel_activate(record):
    if not record.callback:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    callback = record.callback
    callback = callback.replace('{{ATYPE}}', 'activate')
    callback = callback.replace('{{AVALUE}}', '0')

    sign = md5(callback + settings.MOBILE_BAIDU_KEY).hexdigest()

    res = requests.get(callback, params={'sign': sign})
    if res.status_code != 200:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json and res_json['error_code'] != 0:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_NO_PROMOTION}

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    record.callback_response = res.text if res.text else ''
    record.save(update_fields=['active_time', 'update_time', 'callback_response'])

    return {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}


def _dianru_channel_activate(record, client_ip=None):

    params = {'drkey': record.active_key}
    if client_ip:
        params.update({'ip': client_ip})

    res = requests.get(settings.DIANRU_ACTIVATE_URL, params=params)
    if res.status_code != 200:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json['status'] != 1 or res_json['message'] != 'success':
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    record.callback_response = res.text if res.text else ''
    record.save(update_fields=['active_time', 'update_time', 'callback_response'])

    return {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}


def _general_channel_activate(record):

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    update_fields = ['active_time', 'update_time','idfa']
    error_status = 1
    msg = CHANNEL_STATUS.ACT_FAIL_GENERAL

    # 目前接入的渠道中钱咖无回调, 只要调用该接口就认为激活成功
    # make sure those callback required channels get called-back
    # some callback value as string '[callback]'
    channel_logger.info("通用回调函数---")

    headers={
        'Accept-Encoding': 'gzip',
        'Content-Type': 'application/x-www-form-urlencoded',
        'user-agent':"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
    }
    callback = record.callback or None
    if callback and callback.startswith(('http', 'HTTP','https','HTTPS')) and record.callback_type != CHANNEL_CALLBACK_TYPE.NO_CALLBACK:
        res = None

        url = urllib2.unquote(callback)
        try:
            if record.callback_type == CHANNEL_CALLBACK_TYPE.GET_CALLBACK:
                channel_logger.info("{0} callback".format(record.appid))
                res = requests.get(url,timeout=60,headers=headers,verify=_VERIFIED)

            elif record.callback_type == CHANNEL_CALLBACK_TYPE.POST_CALLBACK:
                res = requests.post(url,timeout=60,headers=headers,verify=_VERIFIED)

            if res:
                if res.encoding == 'ISO-8859-1':
                    res.encoding = res.apparent_encoding

                channel_logger.info("{0}".format(res.text))

                record.callback_response = res.text or ''
                update_fields.append('callback_response')
                if res.status_code == 200:
                    error_status = 0
                    msg = CHANNEL_STATUS.ACT_OK
        except:
            # call back just let 3rd party know this, wont affect device ativate
            delayed_activate_callback.delay(url=url, callback_method=record.callback_type, idfa=record.idfa)
            logging_exception()
    else:
        channel_logger.info("无回调---")

    record.save(update_fields=update_fields)
    return {'error': error_status, 'msg': msg}


def _meiyou_channel_activate(record):
    '''
    美柚渠道激活回调
    '''
    # 更新数据库
    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    update_fields = ['active_time', 'update_time']
    error_status = 1
    msg = CHANNEL_STATUS.ACT_FAIL_GENERAL
    # 处理回调
    conv_time = time.time()
    conv_type = 3                # 激活type  3-激活; 4-激活并注册; 5-激活并付费
    request_params = json.loads(record.click_request)
    request_params.update(dict(conv_time=int(conv_time), conv_type=conv_type))
    query_string = urllib.urlencode(request_params)
    signature = auth_util.hash_hmac(settings.MEIYOU_AUTH_KEY, query_string)
    query_string = query_string + '&signature=' + signature
    callback_url = settings.MEIYOU_CALLBACK_URL + query_string

    res = requests.get(callback_url, verify=_VERIFIED)
    if res is not None:
        if res.encoding == 'ISO-8859-1':
            res.encoding = res.apparent_encoding
        record.callback_response = res.text or ''
        update_fields.append('callback_response')

        if res.status_code != 200:
            error_status = 0
            msg = CHANNEL_STATUS.ACT_OK

    record.save(update_fields=update_fields)
    return {'error': error_status, 'msg': msg}


def _youdao_channel_activate(conv_ext, record, conv_type=1):

    query_request = {
        'conv_ext': conv_ext.strip('__'),
        'conv_action': 'ios_activate'
    }

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now
    record.save(update_fields=['active_time', 'update_time'])
    res = requests.get(url='http://conv.youdao.com/api/track', params=query_request)

    if res.status_code != 200:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_FAIL_GENERAL}

    res_json = res.json()
    if res_json and res_json.get('code') and res_json['code'] == 'success':
        return {'error': 0, 'msg': CHANNEL_STATUS.ACT_OK}


def _xiaomi_channel_activate(record):
    '''小米回调激活'''
    secret_key="fmgyKWIhSTbjSAri"#通过小米广告平台获得
    callback_url="http://trail.e.mi.com/api/callback"


    channel_logger.info("xiaomi with......")

    click_request=json.loads(record.click_request)

    time_now = datetime.datetime.now()
    record.active_time = time_now
    record.update_time = time_now

    #转化时间,13位时间戳
    conv_time=int(round(time.time() * 1000))

    callback=click_request.get("callback")
    imei=click_request.get("imei")

    callback_url="{0}?&callback={1}&imei={2}&conv_time={3}".format(callback_url,callback,imei,conv_time)

    channel_logger.info(callback_url)
    #回调小米服务器
    try:
        response=requests.get(callback_url,timeout=60)

        channel_logger.info(response.text)
        if int(response.status_code)!=200:
            channel_logger.info("xiaomi callback fail")
            return JsonResponse({
                "code":1,#0为成功,其他为失败
                "failMsg":"回调服务器错误:{0}".format(response.status_code),#错误信息
            })
        elif int(response.json().get("code"))!=0:
            channel_logger.info("xiaomi callback fail")
            return JsonResponse(response.json())

    except ConnectionError as e:
        channel_logger.info(str(e))
        return JsonResponse({
            "code":1,#0为成功,其他为失败
            "failMsg":"连接小米服务器错误",#错误信息
        })
    channel_logger.info("xiaomi bottom..")
    record.save()


def _wangyi_youdao_channel_activate_new(record):
    """
    网易有道 新版回调
    :param record:
    :return:
    """
    _now = datetime.datetime.now()
    record.active_time = _now
    record.update_time = _now

    update_fields = ['active_time', 'update_time']
    error_status = 1
    msg = CHANNEL_STATUS.ACT_FAIL_GENERAL

    channel_logger.info("调用 网易有道 回调函数---")
    callback = record.callback or None

    if callback and callback.startswith(
            ('http', 'HTTP', 'https', 'HTTPS')
    ) and record.callback_type == CHANNEL_CALLBACK_TYPE.GET_CALLBACK:
        request_params = json.loads(record.click_request)
        platform = record.platform_type  # 设备

        if platform == PLATFORM_CHANNEL.IOS:
            _action = "ios_activate"

        elif platform == PLATFORM_CHANNEL.ANDROID:
            _action = "android_activate"

        else:
            _action = ""

        query_dic = {
            'conv_ext': request_params.get("conv", ""),
            'conv_action': _action,
        }

        callback_url = "{}?{}".format(callback, urllib.urlencode(query_dic))
        try:
            res = requests.get(callback_url)

            if res.encoding == 'ISO-8859-1':
                res.encoding = res.apparent_encoding

            _response_info_str = res.text
            _response_dic = res.json()

            if res.status_code == 200 and _response_dic.get("code", "") == "success":
                error_status = 0
                msg = CHANNEL_STATUS.ACT_OK

            channel_logger.info("网易有道回调! 回调地址:{0},回调结果:{1}".format(callback_url, _response_info_str))

            record.callback_response = _response_info_str or ''
            update_fields.append('callback_response')
        except:
            logging_exception()
            channel_logger.info("网易有道 回调失败。记录id:{}".format(record.id))
    else:
        channel_logger.info("无回调---")

    record.save(update_fields=update_fields)
    return {'error': error_status, 'msg': msg}


def _qutoutiao_channel_activate(record):
    """
    趣头条回调
    :param record:
    :return:
    """
    _now = datetime.datetime.now()
    record.active_time = _now
    record.update_time = _now

    update_fields = ['active_time', 'update_time']
    error_status = 1
    msg = CHANNEL_STATUS.ACT_FAIL_GENERAL

    channel_logger.info("调用 趣头条 回调函数---")
    callback = record.callback or None

    if callback and callback.startswith(
            ('http', 'HTTP', 'https', 'HTTPS')
    ) and record.callback_type == CHANNEL_CALLBACK_TYPE.GET_CALLBACK:

        _url = urllib.unquote(callback)
        up = urlparse.urlparse(_url)

        params_query = urlparse.parse_qsl(up.query)
        params_query.append(("op2", 0))  # 安装app并首次打开

        callback_url = "{http}://{host}{path}?{query}".format(
            http=up.scheme, host=up.netloc, path=up.path, query=urllib.urlencode(params_query)
        )

        try:
            res = requests.get(callback_url)

            if res.encoding == 'ISO-8859-1':
                res.encoding = res.apparent_encoding

            if res.status_code == requests.codes.ok:
                error_status = 0
                msg = CHANNEL_STATUS.ACT_OK
                _response_info_str = res.text

                record.callback_response = _response_info_str or ''
                update_fields.append('callback_response')
            else:
                _response_info_str = ""

            channel_logger.info("趣头条 回调! 回调地址:{0}, 回调状态:{1},回调结果:{2}".format(
                callback_url, res.status_code, _response_info_str)
            )

        except:
            logging_exception()
            channel_logger.info("趣头条 回调失败。记录id:{}".format(record.id))
    else:
        channel_logger.info("无回调---")

    record.save(update_fields=update_fields)
    return {'error': error_status, 'msg': msg}


@bind('statistic/channel_promotion/add_record')
def add_channel_promotion_record(appid, idfa, client_type=CLIENT_TYPE.USER, callback_type=None, callback=None,
                                 click_request=None, active_key=None, platform_type=None, from_shequ=False):
    """
    渠道点击上传接口, hermes调用
    """
    if not all([appid, idfa]):
        return {'error': 1, 'msg': CHANNEL_STATUS.ADD_INVALID_PARAMS}

    if from_shequ:
        if SheQuDevice.objects.filter(device_id=idfa).exists():
            return {'error': 1, 'msg': CHANNEL_STATUS.ADD_ALREADY_ACTIVATED}

    else:
        if Device.objects.filter(device_id=idfa).exists():
            return {'error': 1, 'msg': CHANNEL_STATUS.ADD_ALREADY_ACTIVATED}

    result = {'error': 0, 'msg': CHANNEL_STATUS.ADD_OK}

    try:
        record, created = PromotionChannel.objects.get_or_create(appid=appid, idfa=idfa,
                                                                 defaults={'update_time': datetime.datetime.now()})

        record.callback_type = callback_type if callback_type in CHANNEL_CALLBACK_TYPE \
            else CHANNEL_CALLBACK_TYPE.NO_CALLBACK
        record.callback = callback if callback else ''
        record.click_request = click_request if click_request else ''
        record.client_type = client_type if client_type in CLIENT_TYPE else CLIENT_TYPE.USER
        record.active_key = active_key if active_key else ''
        record.update_time = datetime.datetime.now()
        record.record_from = ''
        record.platform_type = platform_type if platform_type else PLATFORM_CHANNEL.IOS

        record.save()
    except Exception as e:
        param_msg = '{appid},{idfa},{client_type},{callback_type},{callback},{click_request}'
        param_msg = param_msg.format(appid=appid, idfa=idfa, client_type=client_type, callback_type=callback_type,
                                     callback=callback, click_request=click_request)
        msg = 'add-channel-record-exception: %s, %s' % (e.message, param_msg)
        channel_logger.error(msg)
        result.update({'error': 1, 'msg': CHANNEL_STATUS.ADD_FAIL_GENERAL})

    return result


@bind('statistic/guangdiantong')
def guangdiantong_authorization(authorization_code):
    '''
        保存广点通的 authorization_code到redis
    '''
    get_token(authorization_code)
    return


@bind('statistic/channel_promotion/activate_record')
def activate_channel_promotion_record(
        idfa, app_name=None, app_version=None, platform=None, os_version=None,
        device_model=None, uuid=None, client_ip=None, build_number=None,
        client_type=CLIENT_TYPE.USER
):
    """
    渠道激活接口, backend调用
    """

    if not idfa:
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_INVALID_PARAMS}
    channel_logger.info("*"*100)


    #ios的idfa默认为大写,android的idfa默认为小写
    idfa_md5 = md5(idfa).hexdigest()

    channel_logger.info(idfa)
    channel_logger.info(idfa_md5)

    record = PromotionChannel.objects.filter(
        idfa__in=[idfa, idfa_md5], client_type=client_type,
    ).order_by('-update_time').first()



    #如果已激活
    if record and record.active_time:
        channel_logger.info("already activate.")
        return {'error': 1, 'msg': CHANNEL_STATUS.ACT_ALREADY_ACTIVATED}


    # 谷歌推广, 无点击上传记录
    if not record:
        params = {
            'idfa': idfa,
            'app_name': app_name,
            'app_version': app_version,
            'platform': platform,
            'os_version': os_version,
            'device_model': device_model,
            'uuid': uuid,
            'client_ip': client_ip,
            'build_number': build_number
        }
        return _google_channel_activate(**params)

    #更新数据库的idfa
    record.idfa=idfa

    #手机百度推广 需要写在百度推广前面
    if record.appid.startswith(PROMOTION_CHANNEL_NAME.SHOUJIBAIDU):
        channel_logger.info("enter in baidu mobile.")
        func = _mobilebaidu_channel_activate
        params = {'record': record}

    # 百度推广, 回调需要独立的key
    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.BAIDU):
        channel_logger.info("enter in baidu tuiguang")
        func = _baidu_channel_activate
        params = {'record': record}

    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.BAIDUSHOUZHU):
        channel_logger.info("enter in baidu shouzhu")
        func = _baidushouzhu_channel_activate
        params = {'record': record}

    # 点入推广
    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.DIANRU):
        channel_logger.info("enter in dianru!")
        func = _dianru_channel_activate
        params = {'record': record, 'client_ip': client_ip}

    # 网易有道
    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.WANGYIYOUDAO):
        channel_logger.info("enter in wangyi youdao")
        temp = record.click_request
        func = _youdao_channel_activate
        obj = json.loads(temp)
        params = {'conv_ext': obj['conv'], 'record': record, 'conv_type': 1}

    # 网易有道 v2 add in 2019.10.18 不清楚为什么之前加的废弃了
    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.WANGYIYOUDAO_V2):
        channel_logger.info("enter in wang yi you dao - wangyi!")
        params = {"record": record}
        func = _wangyi_youdao_channel_activate_new

    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.MEIYOU):
        channel_logger.info("enter in meiyou")
        func = _meiyou_channel_activate
        params = {'record': record}

    # 趣头条
    elif record.appid.startswith(PROMOTION_CHANNEL_NAME.QUTOUTIAO):
        channel_logger.info("enter in qutoutiao")
        func = _qutoutiao_channel_activate
        params = {"record": record}

    #小米PROMOTION_CHANNEL_NAME.XIAOMI
    elif record.appid.startswith("promotion_xiaomi"):
        channel_logger.info("enter in xiao mi branch...")
        func=_xiaomi_channel_activate
        params = {'record': record}

    elif record.appid.startswith("promotion_guangdiantong"):
        channel_logger.info("enter in guangdiantong---")
        guangdiantong_active(record)

        #激活
        func=_general_channel_activate
        params = {'record': record}

    # 其他渠道, 通用回调
    else:
        channel_logger.info("通用渠道激活----")
        func = _general_channel_activate
        params = {'record': record}

    channel_logger.info("end")
    return func(**params)


