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

import random
import json
import datetime
from datetime import timedelta

from gm_types.gaia import USER_RIGHTS_LEVEL, POINTS_TYPE, CONST_STRINGS
from gm_types.point.error import ERROR
from gm_types.point import ACTIVITY_TYPE, GOODS_TYPE, GOODS_CLAIM_STATUS, GOODS_CLAIM_RESULT

from django.core import serializers
from django.conf import settings
from django.db import models
from django.db.models import Q, Count
from django.db import transaction
from django.utils import timezone

from api.tool.datetime_tool import get_timestamp_or_none
from api.tool.coupon_tool import check_can_get_channel_gift_ids, _try_get_gift

from rpc.cache import ViewRecord
from rpc.tool.error_code import gen, CODES

import point

from api.models import ChannelGift
from point.models import PointActivity, PointActivityGoods, PointUserGoods, PointSnapshot

from .point_activity_manager import get_point_activity_goods_id_to_count, get_channel_gift_id_to_coupon_infos


def _try_get_point_activity(point_activity_id, now=None):
    pa = PointActivity.objects.filter(id=point_activity_id, activity_type=ACTIVITY_TYPE.EXCHANGE,
                                      is_online=True).first()
    #  pa.describe
    if not pa:
        gen(ERROR.POINT_ACTIVITY_NOT_EXIST)

    if now > pa.end_time:
        gen(ERROR.POINT_ACTIVITY_EXPIRE)

    if now < pa.start_time:
        gen(ERROR.POINT_ACTIVITY_NOT_START)

    return pa


def _try_get_point_activity_good(point_activity_goods_id):
    pag = PointActivityGoods.objects.filter(id=point_activity_goods_id, is_online=True).first()
    #  pa.describe
    if not pag:
        return gen(ERROR.POINT_ACTIVITY_GOODS_NOT_EXIST)

    return pag


def _to_exchange_goods_dto(point_activity_goods_ids, user_id=None, check_goods_claim_status=False):
    # result = [{
    #     "activity_goods_id": 1,
    #     "name": "实物：口红",  # 礼品的name
    #     "exchange_count": 0,  # 已经兑换的数量
    #     "points": 200000,  # 兑换需要的美分
    #     "min_user_level": 5,  # 兑换要求最低用户的等级，如果1的话其实等于是任何人都可以兑换了？
    #     "goods_type": GOODS_TYPE.REAL,  # 礼品的name
    #     "thumb": "实物返回礼品小图地址",  # 礼品的name
    #     "image": "实物返回礼品大图地址",  # 礼品的name
    #     "describe": "礼品介绍",
    #     "comment": "温馨提示",
    #
    #     "coupon_claim_start_time": None,
    #     "coupon_claim_end_time": None,
    #     "coupon_claim_time_desc": None,
    #     "coupon_values": None,
    #     "coupon_count": None,
    #
    #     "goods_claim_status": None
    #
    # }, {
    #     "activity_goods_id": 2,
    #     "name": "更美超级美券终极大礼包",
    #     "exchange_count": 10,
    #     "points": 500,
    #     "min_user_level": 1,
    #     "goods_type": GOODS_TYPE.COUPON,  # 礼品的name
    #     "thumb": None,
    #     "image": None,
    #     "describe": "礼品介绍",
    #     "comment": "温馨提示",
    #
    #     "coupon_claim_start_time": get_timestamp_or_none(now),
    #     "coupon_claim_end_time": get_timestamp_or_none(now),
    #     "coupon_claim_time_desc": "领取时间 2017-12-01到2017-12-25",
    #     "coupon_values": 465,
    #     "coupon_count": 6,
    #
    #     "goods_claim_status": None
    # }]

    pags = list(PointActivityGoods.objects.filter(
        id__in=point_activity_goods_ids
    ).select_related('good').order_by('order', '-id'))

    can_get_channel_gift_ids_set = set()
    already_get_channel_gift_ids_set = set()
    point_activity_goods_id_to_count = {}

    all_channel_gift_id = {pa.good.channel_gift_id for pa in pags
                           if pa.good and pa.good.channel_gift_id and pa.good.goods_type == GOODS_TYPE.COUPON}

    if user_id and check_goods_claim_status:
        can_get_channel_gift_ids_set, already_get_channel_gift_ids_set = check_can_get_channel_gift_ids(
            all_channel_gift_id, user_id)
        point_activity_goods_id_to_count = get_point_activity_goods_id_to_count(point_activity_goods_ids, user_id)

    channel_gift_id_to_coupon_infos = get_channel_gift_id_to_coupon_infos(all_channel_gift_id)

    result = []

    for point_activity_goods in pags:
        activity_goods_id = point_activity_goods.id

        add_count = int(ViewRecord(CONST_STRINGS.POINT_ACTIVITY_EXCHANGE)[activity_goods_id] or '0')
        exchange_count = point_activity_goods.base_count + add_count

        good = point_activity_goods.good
        good_dto = {
            "activity_goods_id": activity_goods_id,
            "name": good.name,  # 礼品的name
            "exchange_count": exchange_count,  # 已经兑换的数量
            "points": point_activity_goods.point,  # 兑换需要的美分
            "min_user_level": point_activity_goods.level_limit,  # 兑换要求最低用户的等级，如果1的话其实等于是任何人都可以兑换了？
            "goods_type": good.goods_type,  # 礼品的name
            "thumb": good.thumb,  # 礼品的name
            "image": good.image,  # 礼品的name
            "describe": good.describe,
            "comment": good.comment,

            "coupon_claim_start_time": None,
            "coupon_claim_end_time": None,
            "coupon_claim_time_desc": None,
            "coupon_values": None,
            "coupon_count": None,

            "goods_claim_status": None
        }

        if good.goods_type == GOODS_TYPE.COUPON and good.channel_gift_id in channel_gift_id_to_coupon_infos:
            ci = channel_gift_id_to_coupon_infos[good.channel_gift_id]
            good_dto["coupon_claim_start_time"] = ci["coupon_claim_start_time"]
            good_dto["coupon_claim_end_time"] = ci["coupon_claim_end_time"]
            good_dto["coupon_claim_time_desc"] = ci["coupon_claim_time_desc"]
            good_dto["coupon_values"] = ci["coupon_values"]
            good_dto["coupon_count"] = ci["coupon_count"]

        if user_id and check_goods_claim_status:
            goods_claim_status = GOODS_CLAIM_STATUS.CAN_CLAIM

            #  检查美分商场自己的库存
            if point_activity_goods.current_stock <= 0:
                goods_claim_status = GOODS_CLAIM_STATUS.CANNOT
            else:
                point_activity_goods_count = point_activity_goods_id_to_count.get(activity_goods_id, 0)

                if point_activity_goods_count >= point_activity_goods.limit:
                    goods_claim_status = GOODS_CLAIM_STATUS.ALREADY_CLAIM  # 用户达到领取上限
                else:
                    if good.goods_type == GOODS_TYPE.COUPON:
                        if good.channel_gift_id in already_get_channel_gift_ids_set:
                            goods_claim_status = GOODS_CLAIM_STATUS.ALREADY_CLAIM
                        elif good.channel_gift_id not in can_get_channel_gift_ids_set:
                            goods_claim_status = GOODS_CLAIM_STATUS.CANNOT

            good_dto['goods_claim_status'] = goods_claim_status

        result.append(good_dto)

    return result


def get_exchange_item_list(point_activity_id, now=None):
    if not now:
        now = datetime.datetime.now()

    pa = _try_get_point_activity(point_activity_id, now)

    pag_ids = list(PointActivityGoods.objects.filter(
        activity_id=pa.id, is_online=True
    ).order_by('order', '-id').values_list('id', flat=True)[:pa.placeholder])

    result = _to_exchange_goods_dto(pag_ids)

    return result


def get_exchange_item_detail(point_activity_goods_id, user_id, now=None):
    if not now:
        now = datetime.datetime.now()

    pag = _try_get_point_activity_good(point_activity_goods_id)

    #  这里只是为了保证pa有效的
    pa = _try_get_point_activity(pag.activity_id, now)

    result = _to_exchange_goods_dto([pag.id], user_id=user_id, check_goods_claim_status=True)[0]

    return result


def try_get_exchange_item(point_activity_goods_id, user, now=None):
    if not now:
        now = datetime.datetime.now()

    temp_pag = _try_get_point_activity_good(point_activity_goods_id)

    #  这里需要保证pa有效
    pa = _try_get_point_activity(temp_pag.activity_id, now)

    if temp_pag.current_stock <= 0:
        return GOODS_CLAIM_RESULT.CANNOT, None

    user_level_number = int(user.userextra and user.userextra.user_rights_level or USER_RIGHTS_LEVEL.V1)

    if user_level_number < temp_pag.level_limit:
        return GOODS_CLAIM_RESULT.LEVEL_NOT_ENOUGH, None

    with transaction.atomic():
        #  锁定pag
        pag = PointActivityGoods.objects.select_for_update().select_related('good').get(id=temp_pag.id)

        user_point = point.get_point_for(user)
        if user_point < temp_pag.point:
            return GOODS_CLAIM_RESULT.POINT_NOT_ENOUGH, None

        point_activity_goods_id_to_count = get_point_activity_goods_id_to_count([pag.id], user.id)
        user_good_count = point_activity_goods_id_to_count.get(pag.id, 0)

        if user_good_count >= pag.limit:
            return GOODS_CLAIM_RESULT.ALREADY_CLAIM, None  # 用户达到领取上限

        # 库存检查，美券还要先能拿到才能扣库存
        if pag.current_stock < 1:
            return GOODS_CLAIM_RESULT.CANNOT, None

        if pag.good.goods_type == GOODS_TYPE.COUPON:
            #  还要先看看能不能抢到券
            channel_gift_id = pag.good.channel_gift_id
            cg = ChannelGift.objects.select_for_update().get(id=channel_gift_id)
            success, codes = _try_get_gift(cg, user)

            if not success:
                status = GOODS_CLAIM_RESULT.ALREADY_CLAIM if codes == CODES.COUPON_EXCEED_LIMIT else GOODS_CLAIM_RESULT.CANNOT
                return status, None

        # 能活着到这里，才开始减库存什么

        pag.current_stock -= 1
        pag.save()

        # 写入获取记录

        exchange_use_point = pag.point

        pug = PointUserGoods()
        pug.user_id = user.id
        pug.point = exchange_use_point
        pug.user_level = user_level_number
        pug.activity_goods = pag
        pug.activity = pa

        pug.save()

        point_snapshot = PointSnapshot()
        point_snapshot.user_goods = pug
        point_snapshot.user_exchange = serializers.serialize('json', [pug])
        point_snapshot.goods = serializers.serialize('json', [pag.good])
        point_snapshot.activity = serializers.serialize('json', [pa])
        point_snapshot.activity_goods = serializers.serialize('json', [pag])

        user_extra_json = json.dumps({
            "phone": user.person.phone,
            "address": user.userextra.address,
        })

        point_snapshot.extra = user_extra_json
        point_snapshot.save()

        #  最后扣分，失败可以回滚

        point.remove(
            user_id=user.id,
            reason=POINTS_TYPE.POINTS_EXCHANGE,
            point=exchange_use_point,
        )

        #  完成操作之前去加那个没用的兑换数

        view = ViewRecord(CONST_STRINGS.POINT_ACTIVITY_EXCHANGE)
        exchange_count = int(view[pag.id] or '0')

        add_numbers = [1, 3, 5, 7, 9]
        add_count = add_numbers[random.randint(0, len(add_numbers)-1)]

        view[pag.id] = exchange_count + add_count

        return GOODS_CLAIM_RESULT.SUCCESS, pag.good.goods_type
