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

import hashlib

import datetime

from django.conf import settings
from django.db.models import Q
from gm_types.gaia import (
    PAGE_TYPE,
    POPUPAD_USER_TYPE,
    PUSHCOUPON_USER_STATUS,
    SLIDE_PAYMENT_TYPE,
    WORLD_AREA_TYPE,
    PLATFORM_CHOICES,
    SOURCE_POSITION_DEVICE_TYPE,
    GRAY_TYPE,
)
from gm_types.error import ERROR

from api.models.greetpopup import GreetingPopup
from api.models.pushtask import PushCouponUser
from api.models import City
from api.tool.log_tool import logging_exception
from api.tool.user_tool import get_user_from_context, user_have_payment, is_new_user_local, \
    new_get_user_and_payment_info
from api.tool.datetime_tool import get_timestamp, add_day
from api.tool.city_tool import is_oversea
from api.tool.geo_tool import get_city_by_id

from rpc.cache import popup_cache
from rpc.decorators import bind_context, cache_page, bind
from rpc.tool.error_code import gen


def check_gray(gray_value, device_id, base=20):
    if not any([device_id, gray_value]):
        return True

    gray_value = list(map(int, gray_value.split(',')))
    target = int(hashlib.sha1(device_id).hexdigest(), 16) % base
    if target in gray_value:
        return True

    return False


@bind_context('api/welcome/info', login_required=False)
def get_welcome_info(
        ctx,
        page_type,
        start_num=0,
        user_type=POPUPAD_USER_TYPE.ALL,
        channel=None,
        city_id=None,
        device_id=None,
        platform='',
        is_diary_user=True
):
    """
    获取后台配置开屏页或者首页弹窗等数据

    is_diary_user: 是否是有日记的用户
    """
    result = []
    now_t = datetime.datetime.now()

    # get user_type according to platform & device_id
    user = get_user_from_context(ctx)
    new_user_payment_info = new_get_user_and_payment_info(user, platform, device_id)
    new_user = new_user_payment_info.get('is_new_user')
    user_type = POPUPAD_USER_TYPE.NEW_USER if new_user else POPUPAD_USER_TYPE.OLD_USER

    # init_query_condition
    query = Q(type=page_type) & Q(start_time__lte=now_t) & Q(end_time__gte=now_t) & Q(is_online=True)

    user_type_query = Q(popup_user_type__in=[user_type, POPUPAD_USER_TYPE.ALL])

    # all area visiable
    city_query = Q(cities__isnull=True, regions__isnull=True)
    if not city_id or city_id in WORLD_AREA_TYPE or is_oversea([city_id])[0]:    # 无定位/全部地区/海外用户
        pass
    else:
        city_query |= Q(cities=city_id)
        region = None
        city_obj = get_city_by_id(city_id)
        if city_obj and city_obj.province:
            try:
                region = city_obj.province.region
            except:
                pass
        if region:
            city_query |= Q(regions=region)

    query &= user_type_query
    query &= city_query

    is_sustain = False
    """
    资源定向为需求，开屏和弹窗广告都需要判断有无支付，增加设备判断
    """
    if new_user_payment_info['have_payment']:
        payment_type = SLIDE_PAYMENT_TYPE.HAVE_PAYMENT
    else:
        payment_type = SLIDE_PAYMENT_TYPE.NO_PAYMENT
    if platform == PLATFORM_CHOICES.IPHONE:
        query &= Q(device_type__in=[SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE, SOURCE_POSITION_DEVICE_TYPE.IOS_DEVICE])
    elif platform == PLATFORM_CHOICES.ANDROID:
        query &= Q(device_type__in=[SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE, SOURCE_POSITION_DEVICE_TYPE.ANDROID])
    else:
        query &= Q(device_type=SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE)
    user_payment_query = Q(payment_type__in=[payment_type, SLIDE_PAYMENT_TYPE.ALL_PAYMENT])
    query &= user_payment_query
    if page_type == PAGE_TYPE.GREETING:    # 开屏页广告
        if not GreetingPopup.objects.filter(query).exists():
            return []
        add_sum = GreetingPopup.objects.filter(query).count()
        welcome_infos = GreetingPopup.objects.filter(query).order_by('rank')[(start_num % add_sum)]
        if welcome_infos.gray_type == GRAY_TYPE.DIVIDE_20:
            if not check_gray(welcome_infos.gray_value, device_id):
                return result

        result.append(welcome_infos.to_dict())
        for r in result:
            r.update({'is_sustain': is_sustain})
        return result

    elif page_type == PAGE_TYPE.POPUP:
        """
        7625修订: 新增用户是否支付和渠道维度
        """
        channel_query = Q(channels='')
        if channel:
            channel_query |= Q(channels__icontains=channel)
        query &= channel_query

        popup_pages = GreetingPopup.objects.filter(query).order_by('rank', '-start_time').distinct()
        channel_popup_pages, normal_popup_pages = [], []

        for page in popup_pages:
            if page.gray_type == GRAY_TYPE.DIVIDE_20:
                if not check_gray(page.gray_value, device_id): continue

            if page.channels and page.is_sustain:
                channel_popup_pages.append(page)
            else:
                normal_popup_pages.append(page)

        # 1. 如果包含渠道弹窗, 只显示rank最前的弹窗。
        # 2. 持续弹窗和非持续弹窗, 按rank顺序依次展示。
        result_pages = []
        if channel_popup_pages:
            result_pages = [channel_popup_pages[0], ]
        else:

            def is_diary_match_popup(popup_id):
                return popup_id == settings.DIARY_MATCH_POPUP_ID

            today = datetime.date.today()
            expire_limit = add_day(today, settings.POPUP_CACHE_LIMIT_DAYS)  # 添加弹窗过期时间限制，防止缓存数据过多
            for npp in normal_popup_pages:
                npp_id = str(npp.id)
                # 没有日记的用户不展示日记大赛弹窗
                if not is_diary_user and is_diary_match_popup(npp.id):
                    continue
                if popup_cache.exists(npp_id):
                    if not popup_cache.sismember(npp_id, device_id):    # 如果之前没有为该用户展示过该弹窗
                        result_pages = [npp, ]
                        popup_cache.sadd(npp_id, device_id)
                        break
                    elif npp.is_sustain:    # 如果轮到持续弹窗则展示持续弹窗
                        result_pages = [npp, ]
                        break
                else:   # 某一个弹窗还未被任何用户查看过，则展示该弹窗
                    result_pages = [npp, ]
                    popup_cache.sadd(npp_id, device_id)
                    expire_time = min(get_timestamp(expire_limit), get_timestamp(npp.end_time))
                    popup_cache.expireat(npp_id, expire_time)
                    break

            # 如果当前有效的弹窗都已经展示过，则从头开始展示
            if not result_pages and normal_popup_pages:
                for npp in normal_popup_pages:
                    popup_cache.srem(str(npp.id), device_id)

                popup = normal_popup_pages[0]
                if is_diary_match_popup(popup.id) and not is_diary_user:
                    normal_popup_pages = normal_popup_pages[1:]
                    if normal_popup_pages:
                        popup = normal_popup_pages[0]
                    else:
                        popup = None

                if popup:
                    result_pages = [popup, ]
                    popup_cache.sadd(str(popup.id), device_id)
                    expire_time = min(get_timestamp(expire_limit), get_timestamp(popup.end_time))
                    popup_cache.expireat(str(popup.id), expire_time)

        result = [x.to_dict() for x in result_pages]

        return result
    else:
        raise gen(ERROR.PAGE_TYPE_NOT_FOUND)


@bind_context('api/welcome/coupon/info', login_required=True)
def get_welcome_coupon_info(ctx):
    user = get_user_from_context(ctx)

    query = Q(user_id=user.id) & Q(has_show_popup=False) & \
        Q(push_coupon_status=PUSHCOUPON_USER_STATUS.SUCCESS) & Q(push_coupon__push_popup=True)
    time_now = datetime.datetime.now()
    query &= Q(get_coupon_time__isnull=False) & Q(get_coupon_time__lte=time_now)

    coupon_info_set = PushCouponUser.objects.filter(query).order_by('-get_coupon_time')
    coupon_data = coupon_info_set.first()

    if not coupon_info_set or not coupon_data:
        return {'error': 1, 'message': 'no coupon data to popup', 'data': {}}

    coupon_info_set.update(has_show_popup=True)

    data = {'id': coupon_data.id, 'image': coupon_data.push_coupon.popup_img}
    result = {'error': 0, 'message': '', 'data': data}

    return result


@bind('api/index/popup/get')
def get_popup_by_id(popup_id):
    """ 根据首页弹窗id获取弹窗数据 """
    if not popup_id:
        return {}
    try:
        popup_page = GreetingPopup.objects.get(id=popup_id, is_online=True)
    except GreetingPopup.DoesNotExist:
        return {}

    return popup_page.to_dict()
