# -*- coding: utf-8 -*-

from __future__ import division

import random

from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.db import transaction
from django_logit import logit
from django_response import response
from pywe_miniapp import get_phone_number
from pywe_storage import RedisStorage
from TimeConvert import TimeConvert as tc

from account.models import UserInfo
from api.hb_views import exec_send_jsapi_hb
from logs.models import MchInfoEncryptLogInfo
from mch.models import (ActivityInfo, AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo,
                        LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo)
from statistic.models import ConsumeModelSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo
from utils.error.errno_utils import (AdministratorStatusCode, OperatorStatusCode, ProductBrandStatusCode,
                                     ProductModelStatusCode, UserStatusCode)
from utils.redis.connect import r
from utils.redis.rkeys import MINI_PROGRAM_GIS_LIST, REDPACK_WAITING_SEND_LIST


WECHAT = settings.WECHAT


@logit
def optor_login_api(request):
    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
    phone = request.POST.get('phone', '')
    password = request.POST.get('password', '')

    try:
        operator = OperatorInfo.objects.get(phone=phone, brand_id=brand_id, status=True)
    except OperatorInfo.DoesNotExist:
        return response(OperatorStatusCode.OPERATOR_NOT_FOUND)

    if operator.user_status == OperatorInfo.DISABLED:
        return response(OperatorStatusCode.OPERATOR_NOT_ACTIVATED)
    elif operator.user_status == OperatorInfo.DELETED:
        return response(OperatorStatusCode.OPERATOR_HAS_DELETED)

    if not check_password(password, operator.encryption):
        return response(OperatorStatusCode.OPERATOR_PASSWORD_ERROR)

    return response(200, 'Optor Login Success', u'操作员登录成功', data=operator.kododata)


@logit
def admin_login_api(request):
    phone = request.POST.get('phone', '')
    password = request.POST.get('password', '')

    try:
        administrator = AdministratorInfo.objects.get(phone=phone, status=True)
    except AdministratorInfo.DoesNotExist:
        return response(AdministratorStatusCode.ADMINISTRATOR_NOT_FOUND)

    if administrator.user_status == AdministratorInfo.DISABLED:
        return response(AdministratorStatusCode.ADMINISTRATOR_NOT_ACTIVATED)
    elif administrator.user_status == AdministratorInfo.DELETED:
        return response(AdministratorStatusCode.ADMINISTRATOR_HAS_DELETED)

    if not check_password(password, administrator.encryption):
        return response(AdministratorStatusCode.ADMINISTRATOR_PASSWORD_ERROR)

    request.session['admin_id'] = administrator.admin_id

    return response(200, 'Admin Login Success', u'管理员登录成功', data={
        'admin_id': administrator.admin_id,
        'admin_type': administrator.admin_type,
        'qrurl': settings.KODO_CLERK_AUTH_URL.format(administrator.brand_id),
    })


@logit
def bmd_infos(request):
    optor_id = request.POST.get('optor_id', '')

    try:
        operator = OperatorInfo.objects.get(operator_id=optor_id, status=True)
    except OperatorInfo.DoesNotExist:
        return response(OperatorStatusCode.OPERATOR_NOT_FOUND)

    if operator.user_status == OperatorInfo.DISABLED:
        return response(OperatorStatusCode.OPERATOR_NOT_ACTIVATED)

    brands = BrandInfo.objects.filter(brand_id=operator.brand_id, status=True).order_by('position')
    brands = [brand.data for brand in brands]

    tmpmodels = ModelInfo.objects.filter(brand_id=operator.brand_id, display=True, status=True).order_by('position')
    models = [model.data for model in tmpmodels]
    # jancodes = {model.jancode: model.data for model in tmpmodels}

    distributors = DistributorInfo.objects.filter(brand_id=operator.brand_id, status=True).order_by('position')
    distributors = [distributor.data for distributor in distributors]

    return response(200, data={
        'optor_id': operator.operator_id,
        'brands': brands,
        'models': models,
        # 'jancodes': jancodes,
        'distributors': distributors,
    })


@logit
def brands_list(request):
    brands = BrandInfo.objects.filter(status=True).order_by('position')
    brands = [brand.data for brand in brands]

    return response(200, data={
        'brands': brands,
    })


@logit
def models_list(request):
    models = ModelInfo.objects.filter(status=True).order_by('position')
    models = [model.data for model in models]

    return response(200, data={
        'models': models,
    })


@logit
def distributors_list(request):
    distributors = DistributorInfo.objects.filter(status=True).order_by('position')
    distributors = [distributor.data for distributor in distributors]

    return response(200, data={
        'distributors': distributors,
    })


@logit
def upgrade_api(request):
    """ APP 升级 """
    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
    src = request.POST.get('src', '')

    if src == 'datascreen':
        latestappmodel = LatestAppScreenInfo
    else:
        latestappmodel = LatestAppInfo

    try:
        appinfo = latestappmodel.objects.filter(brand_id=brand_id, status=True)[0].adr
    except IndexError:
        appinfo = {
            'latest_version_code': '',
            'latest_version_name': '',
            'latest_url': '',
        }

    return response(200, 'Get Latest App Success', u'获取最新版信息成功', {
        'appinfo': appinfo,
    })


def getPhoneNumber(request):
    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)

    user_id = request.POST.get('user_id', '')

    wxcfg = WECHAT.get('{}:MINIAPP'.format(brand_id), {})

    appid = wxcfg.get('appID')
    secret = wxcfg.get('appsecret')

    # Just for compatible because of store session_key has changed
    session_key = None if user_id else RedisStorage(r).get('{0}:{1}:sessionKey'.format(appid, ''))

    iv = request.POST.get('iv', '')
    encryptedData = request.POST.get('encryptedData', '')

    # {
    #     "phoneNumber": "13580006666",
    #     "purePhoneNumber": "13580006666",
    #     "countryCode": "86",
    #     "watermark":
    #         {
    #             "appid": "APPID",
    #             "timestamp": TIMESTAMP
    #         }
    # }
    phone_number = get_phone_number(appid=appid, secret=secret, unid=user_id, session_key=session_key, encryptedData=encryptedData, iv=iv, storage=RedisStorage(r))

    return phone_number.get('purePhoneNumber', '')


@logit(res=True)
def consumer_phone_api(request):
    return response(200, 'Get Consumer Phone Success', u'获取消费者手机号成功', {
        'purePhoneNumber': getPhoneNumber(request),
    })


@logit(res=True)
@transaction.atomic
def consumer_info_api(request):
    user_id = request.POST.get('user_id', '')
    iv = request.POST.get('iv', '')
    encryptedData = request.POST.get('encryptedData', '')
    lat = request.POST.get('lat', .0)
    lon = request.POST.get('lon', .0)
    brandID = request.POST.get('brand_id', '') or request.POST.get('BrandID', '')
    modelID = request.POST.get('ModelID', '')
    distributorID = request.POST.get('DistributorID', '')
    serialNo = request.POST.get('SerialNo', '')
    verifyResult = request.POST.get('verifyResult', '')
    purePhoneNumber = request.POST.get('purePhoneNumber', '')

    if lat == 'undefined':
        lat = .0
    if lon == 'undefined':
        lon = .0

    # purePhoneNumber = purePhoneNumber or getPhoneNumber(request)

    # 校验用户是否存在
    try:
        user = UserInfo.objects.get(user_id=user_id)
    except UserInfo.DoesNotExist:
        return response(UserStatusCode.USER_NOT_FOUND)

    # Tips: Change to update user's phone by membercard
    # 更新用户手机号
    # user.phone = purePhoneNumber
    # user.save()

    try:
        brand = BrandInfo.objects.get(brand_id=brandID)
    except BrandInfo.DoesNotExist:
        brand = None

    if not brand:
        try:
            brand = BrandInfo.objects.get(pk=brandID)
        except BrandInfo.DoesNotExist:
            return response(ProductBrandStatusCode.BRAND_NOT_FOUND)
        except ValueError:
            return response(ProductBrandStatusCode.BRAND_NOT_FOUND)

    try:
        model = ModelInfo.objects.get(pk=modelID)
    except ModelInfo.DoesNotExist:
        return response(ProductModelStatusCode.MODEL_NOT_FOUND)
    except ValueError:
        return response(ProductModelStatusCode.MODEL_NOT_FOUND)

    # try:
    #     distributor = DistributorInfo.objects.get(pk=distributorID)
    # except DistributorInfo.DoesNotExist:
    #     return response(ProductDistributorStatusCode.DISTRIBUTOR_NOT_FOUND)
    # except ValueError:
    #     return response(ProductDistributorStatusCode.DISTRIBUTOR_NOT_FOUND)

    dupload = ConsumeInfoSubmitLogInfo.objects.filter(
        brand_id=brand.brand_id,
        model_id=model.model_id,
        # distributor_id=distributor.distributor_id,
        distributor_id='',
        serialNo=serialNo,
        verifyResult=1,
        test_user=False,
    ).exists()

    if dupload:
        act = None
        during_activity = False
    else:
        act = ActivityInfo.objects.filter(status=True).order_by('-pk').first()
        during_activity = True if act and act.has_unexpired_activity(model.model_uni_name) else False

    # 记录用户信息提交记录
    log = ConsumeInfoSubmitLogInfo.objects.create(
        user_id=user_id,
        phone=purePhoneNumber,
        iv=iv,
        encryptedData=encryptedData,
        lat=lat,
        lon=lon,
        brand_id=brand.brand_id,
        brand_name=brand.brand_name,
        model_id=model.model_id,
        model_name=model.model_name,
        # distributor_id=distributor.distributor_id,
        # distributor_name=distributor.distributor_name,
        distributor_id='',
        distributor_name='',
        serialNo=serialNo,
        verifyResult=verifyResult,
        dupload=dupload,
        submit_during_activity=during_activity,
        activity_id=act.pk if during_activity else 0,
        coupon_expire_at=act.coupon_expire_at if during_activity else None,
        coupon_value=act.coupon_value if during_activity else 0,
        test_user=user.test_user,
    )

    if (not settings.CHECK_DUPLOAD_ENABLED) or (not user.test_user and not dupload):
        # TODO: Make statistic async
        ymd = tc.local_string(format='%Y%m%d')

        cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd,
        )
        cusi.users = list(set(cusi.users + [log.user_id]))
        cusi.num = len(cusi.users)
        cusi.save()
        cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd[:6],
        )
        cusi.users = list(set(cusi.users + [log.user_id]))
        cusi.num = len(cusi.users)
        cusi.save()
        cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd[:4],
        )
        cusi.users = list(set(cusi.users + [log.user_id]))
        cusi.num = len(cusi.users)
        cusi.save()

        # 日销量统计
        cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd,
        )
        cssi.num += 1
        cssi.save()
        # 月销量统计
        cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd[:6],
        )
        cssi.num += 1
        cssi.save()
        # 年销量统计
        cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            ymd=ymd[:4],
        )
        cssi.num += 1
        cssi.save()

        # 日型号销量统计
        cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            model_name=model.model_uni_name,
            ymd=ymd,
        )
        cmssi.num += 1
        cmssi.save()
        # 月型号销量统计
        cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            model_name=model.model_uni_name,
            ymd=ymd[:6],
        )
        cmssi.num += 1
        cmssi.save()
        # 年型号销量统计
        cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
            brand_id=brand.brand_id,
            model_name=model.model_uni_name,
            ymd=ymd[:4],
        )
        cmssi.num += 1
        cmssi.save()

        r.rpushjson(MINI_PROGRAM_GIS_LIST, {
            'brand_id': log.brand_id,
            'user_id': log.user_id,
            'lat': log.lat,
            'lon': log.lon,
            'phone': log.phone,
            'ymd': ymd,
        })

    try:
        elog = MchInfoEncryptLogInfo.objects.select_for_update().get(sn=serialNo)
    except MchInfoEncryptLogInfo.DoesNotExist:
        elog = None
    except MchInfoEncryptLogInfo.MultipleObjectsReturned:
        elog = None

    if elog and (not dupload) and elog.is_send_redpack and (not elog.has_send_redpack) and (elog.redpack_amount or elog.redpack_max_amount):
        amount = elog.redpack_amount
        if elog.redpack_max_amount:
            amount = random.randint(100, elog.redpack_max_amount)
        if user.openid:
            exec_send_jsapi_hb(user, elog, amount)
        else:
            r.rpushjson(REDPACK_WAITING_SEND_LIST, {
                'sn': serialNo,
                'user_id': user.user_id,
                'amount': amount,
            })

    return response(200, 'Submit Consumer Info Success', u'提交消费者信息成功')


@logit(res=True)
@transaction.atomic
def consumer_snlist_api(request):
    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
    user_id = request.POST.get('user_id', '')

    # 校验用户是否存在
    try:
        user = UserInfo.objects.get(user_id=user_id)
    except UserInfo.DoesNotExist:
        return response(UserStatusCode.USER_NOT_FOUND)

    # 用户信息提交列表
    logs = ConsumeInfoSubmitLogInfo.objects.filter(user_id=user_id, brand_id=brand_id, status=True).distinct()
    seen = set()
    seen_add = seen.add
    logs = [log.data for log in logs if not (log.serialNo in seen or seen_add(log.serialNo))]

    return response(200, 'Get Consumer Submit List Success', u'获取消费者提交列表成功', {
        'logs': logs,
    })
