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

from django.conf import settings
from django.db import transaction
from django.shortcuts import HttpResponse
from logit import logit
from paginator import pagination
from pywe_exception import WeChatPayException
from pywe_pay import WeChatPay
from pywe_pay_notify import check_pay_notify
from pywe_response import WXPAY_NOTIFY_FAIL, WXPAY_NOTIFY_SUCCESS
from pywe_sign import check_signature
from TimeConvert import TimeConvert as tc

from account.models import UserIncomeExpensesInfo, UserInfo
from group.models import GroupPhotoInfo, GroupPhotoOrderInfo
from pay.models import OrderInfo
from photo.models import PhotosInfo
from utils.error.errno_utils import (GroupPhotoStatusCode, OrderStatusCode, UserStatusCode, WechatStatusCode,
                                     WithdrawStatusCode)
from utils.error.response_utils import response
from utils.price_utils import get_group_photo_price
from utils.redis.rbrief import set_brief_info
from utils.redis.rorder import set_lensman_order_record
from utils.wx_utils import get_trade_type, get_user_openid


WECHAT = settings.WECHAT


@logit
@transaction.atomic
def wx_order_create_api(request):
    """ 订单创建 """
    group_id = request.POST.get('group_id', '')
    user_id = request.POST.get('user_id', '')
    photo_id = request.POST.get('photo_id', '')
    photo_type = request.POST.get('photo_type', 'nomark')  # nomark for 去除水印, origin for 获取高清图

    photo_type_int = OrderInfo.ORIGIN if photo_type == 'origin' else OrderInfo.NOMARK

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

    # 群组照片校验
    try:
        group_photo = GroupPhotoInfo.objects.get(photo_id=photo_id, status=True)
    except GroupPhotoInfo.DoesNotExist:
        return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND)

    # 判断是否重复购买
    if OrderInfo.objects.filter(photo_id=photo_id, photo_type=photo_type_int, from_uid=user_id, pay_status=OrderInfo.PAID, status=True).exists():
        return response(OrderStatusCode.WX_ORDER_PAID_ALREADY_EXISTS)

    body = request.POST.get('body', '')  # 商品描述
    total_fee = int(request.POST.get('total_fee', 0))  # 总金额，单位分

    # 金额校验
    if get_group_photo_price(group_photo, photo_type) != total_fee:
        return response(OrderStatusCode.FEE_CHECK_FAIL)

    # 获取 from_uid, to_uid
    from_uid = user_id
    to_uid = group_photo.lensman_id or group_photo.user_id

    # JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里
    trade_type = request.POST.get('trade_type', '')

    # 根据 trade_type 获取 wechat 配置
    wxcfg = WECHAT.get(trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wxcfg.get('appID'), wxcfg.get('apiKey'), wxcfg.get('mchID'))

    # 生成订单
    order = OrderInfo.objects.create(
        group_id=group_id,
        photo_id=photo_id,
        lensman_photo_id=group_photo.lensman_photo_id,
        photo_type=photo_type_int,
        from_uid=from_uid,
        to_uid=to_uid,
        session_id=group_photo.session_id,
        total_fee=total_fee,
        trade_type=trade_type,
    )

    try:
        prepay_data = wxpay.order.create(
            body=body,
            notify_url=settings.API_DOMAIN + '/wx/notify_url',
            out_trade_no=order.order_id,
            total_fee=total_fee,
            trade_type=get_trade_type(trade_type),
            openid=get_user_openid(user, trade_type),  # 可选，用户在商户appid下的唯一标识。trade_type=JSAPI，此参数必传
        )
    except WeChatPayException as e:
        order.unifiedorder_result = e.message
        order.save()
        return response(OrderStatusCode.WX_UNIFIED_ORDER_FAIL)

    prepay_id = prepay_data.get('prepay_id', '')
    order.prepay_id = prepay_id
    order.save()

    if trade_type == 'JSAPI' or trade_type == 'MINIAPP':
        wxpay_params = wxpay.jsapi.get_jsapi_params(prepay_id)
    elif trade_type == 'APP':
        wxpay_params = wxpay.order.get_appapi_params(prepay_id)

    return response(200, 'Order Create Success', u'订单创建成功', {
        'order_id': order.order_id,
        'prepay_id': prepay_id,
        'wxpay_params': wxpay_params,
    })


def order_paid_success(order):
    if order.pay_status == OrderInfo.PAID:
        return

    if order.photo_type == OrderInfo.NOMARK:
        order.photo_status = OrderInfo.FETCHED
    order.pay_status = OrderInfo.PAID
    order.paid_at = tc.utc_datetime()
    order.save()

    porder, created = GroupPhotoOrderInfo.objects.select_for_update().get_or_create(
        group_id=order.group_id,
        session_id=order.session_id,
        user_id=order.from_uid,
        photo_id=order.photo_id,
        lensman_photo_id=order.lensman_photo_id,
    )
    photo = PhotosInfo.objects.get(
        lensman_id=order.to_uid,
        session_id=order.session_id,
        photo_id=order.lensman_photo_id,
    )
    if order.photo_type == OrderInfo.NOMARK:
        porder.m_photo_path = photo.m_photo_path
    elif order.photo_type == OrderInfo.ORIGIN:
        porder.r_photo_path = photo.r_photo_path
    porder.save()

    set_lensman_order_record(porder)

    to_uid = order.to_uid
    total_fee = order.total_fee

    try:
        user = UserInfo.objects.select_for_update().get(user_id=to_uid)
    except UserInfo.DoesNotExist:
        return

    if order.photo_type == OrderInfo.NOMARK:
        # 余额增加
        amount, freeze_income_amount = total_fee, 0
        user.balance += amount
        # Redis 数值更新
        set_brief_info(to_uid, order.photo_type, total_fee)
        # 余额记录
        UserIncomeExpensesInfo.objects.create(
            user_id=to_uid,
            photo_id=order.photo_id,
            type=UserIncomeExpensesInfo.INCOME,
            amount=amount,
            balance=user.balance,
            freeze_income_amount=freeze_income_amount,
            freeze_income_balance=user.freeze_income_balance,
            remark=u'图片购买',
        )
    elif order.photo_type == OrderInfo.ORIGIN:
        amount, freeze_income_amount = 0, total_fee
        user.freeze_income_balance += freeze_income_amount
    user.save()


def order_paid_fail(order):
    if order.pay_status == OrderInfo.FAIL:
        return

    order.pay_status = OrderInfo.FAIL
    order.save()


@logit
@transaction.atomic
def wx_order_query_api(request):
    """ 订单查询 """
    order_id = request.POST.get('order_id', '')
    transaction_id = request.POST.get('transaction_id', '')

    try:
        order = OrderInfo.objects.select_for_update().get(order_id=order_id, status=True)
    except OrderInfo.DoesNotExist:
        return response(OrderStatusCode.WX_ORDER_NOT_FOUND)

    if order.pay_status == OrderInfo.PAID:
        return response(200, 'Order Pay Success', u'订单支付成功')
    elif order.pay_status == OrderInfo.FAIL:
        return response(OrderStatusCode.WX_ORDER_PAY_FAIL)

    # 根据 trade_type 获取 wechat 配置
    wxcfg = WECHAT.get(order.trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wxcfg.get('appID'), wxcfg.get('apiKey'), wxcfg.get('mchID'))

    # 订单查询
    query_data = wxpay.order.query(transaction_id, order_id)
    # 签名校验
    if not check_signature(query_data, wxcfg.get('apiKey')):
        return response(OrderStatusCode.SIGN_CHECK_FAIL)

    order.notify_msg = query_data
    order.transaction_id = query_data.get('transaction_id', '')
    order.save()

    # 交易状态
    trade_state = query_data.get('trade_state')
    # 订单状态判断更新
    if trade_state == 'SUCCESS':  # 订单支付成功
        order_paid_success(order)
        return response(200, 'Order Pay Success', u'订单支付成功')
    elif trade_state == 'NOTPAY':  # 订单未支付
        return response(OrderStatusCode.WX_ORDER_NOT_PAY)
    elif trade_state == 'USERPAYING':  # 订单支付中
        return response(OrderStatusCode.WX_ORDER_PAYING)
    else:  # 订单支付失败
        order_paid_fail(order)
        return response(OrderStatusCode.WX_ORDER_PAY_FAIL)


@logit
@transaction.atomic
def wx_order_list_api(request):
    """ 订单列表 """
    user_id = request.POST.get('user_id', '')
    page = int(request.POST.get('page', 1))
    num = int(request.POST.get('num', settings.ORDER_NUM_PER_PAGE))

    orders = OrderInfo.objects.filter(from_uid=user_id, pay_status=OrderInfo.PAID, status=True).order_by('-pk')
    orders, left = pagination(orders, page, num)
    orders = [order.data(user_id) for order in orders]

    return response(200, 'Get Order List Success', u'获取订单列表成功', {
        'orders': orders,
        'left': left,
    })


@logit
@transaction.atomic
def wx_order_detail_api(request):
    """ 订单详情 """
    user_id = request.POST.get('user_id', '')
    order_id = request.POST.get('order_id', '')

    try:
        order = OrderInfo.objects.get(order_id=order_id, status=True)
    except OrderInfo.DoesNotExist:
        return response(OrderStatusCode.WX_ORDER_NOT_FOUND)

    if user_id not in [order.from_uid, order.to_uid]:
        return response(OrderStatusCode.NO_DETAIL_PERMISSION)

    return response(200, 'Get Order Detail Success', u'获取订单详情成功', order.data(user_id))


@logit
@transaction.atomic
def wx_notify_url_api(request):
    """ 支付异步通知回调地址 """
    notify_data, success = check_pay_notify(request.body, wx_configs=settings.WECHAT)
    if not success:
        return HttpResponse(WXPAY_NOTIFY_FAIL)

    try:
        order = OrderInfo.objects.select_for_update().get(order_id=notify_data.get('out_trade_no', ''), status=True)
    except OrderInfo.DoesNotExist:
        return HttpResponse(WXPAY_NOTIFY_FAIL)

    order.notify_msg = request.body
    order.transaction_id = notify_data.get('transaction_id', '')
    order.save()

    result_code = notify_data.get('result_code', '')
    if result_code == 'SUCCESS':
        order_paid_success(order)
    else:
        order_paid_fail(order)

    return HttpResponse(WXPAY_NOTIFY_SUCCESS)


@logit
@transaction.atomic
def wx_balance_withdraw_api(request):
    user_id = request.POST.get('user_id', '')

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

    # JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里
    trade_type = request.POST.get('trade_type', '')
    # TRANSFER--企业付款、PACKET--现金红包, 余额提现接口withdraw_type的传参可参考这里
    withdraw_type = request.POST.get('withdraw_type', 'TRANSFER')
    amount = int(request.POST.get('amount', 0))

    if not user.openid:
        return response(WechatStatusCode.OPENID_NOT_FOUND)

    if user.balance < amount:
        return response(WithdrawStatusCode.BALANCE_NOT_ENOUGH)

    # 根据 trade_type 获取 wechat 配置
    wxcfg = WECHAT.get(trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wxcfg.get('appID'), wxcfg.get('apiKey'), wxcfg.get('mchID'), mch_cert=wxcfg.get('mch_cert'), mch_key=wxcfg.get('mch_key'))

    if withdraw_type == 'TRANSFER':
        ret_data = wxpay.transfer.transfer(user.openid, amount, u'摄影师余额提现，企业付款', check_name='NO_CHECK')
    elif withdraw_type == 'PACKET':
        wxrpk = wxcfg.get('redpack', {})
        ret_data = wxpay.redpack.send(
            user.openid,
            amount,
            send_name=wxrpk.get('SEND_NAME'),
            nick_name=wxrpk.get('NICK_NAME'),
            act_name=wxrpk.get('ACT_NAME'),
            wishing=wxrpk.get('WISHING'),
            remark=wxrpk.get('REMARK'),
        )

    # 根据 ret_data 判断是否提现成功, 成功则减余额, 失败则提示
    user.balance -= amount
    user.save()

    return response(200, 'Withdraw Success', u'提现成功', {})
