# coding=utf-8
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Remove `managed = False` lines for those models you wish to give write DB access
# Feel free to rename the models, but don't rename db_table values or field names.
#
# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'
# into your database.
from __future__ import unicode_literals, absolute_import, print_function

import json
import datetime
import calendar
import redis

from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
from gm_types.gaia import SEARCH_KEYWORDS_TYPE, SEARCH_KEYWORDS_POSITION, HOT_SEARCH_JUMP_TYPE
from gm_types.user_hierarchy import EventType
from gm_upload import IMG_TYPE, ImgUrlField
from gm_protocol import GmProtocol

from api.models.types import POINTS_TYPE
from api.models.types import PLATFORM_CHOICES
from api.models.types import DEFAULT_LAST_VIEW_DATETIME
from api.models.types import BLOCK_USER_REASON
from rpc.cache import gadget_cache
from .area import Province, City, Region
from rpc.tool.dict_mixin import to_dict
from mimas.event_manager import EventDispatcher

import point
from mimas.tasks import send_event_task


class Android(models.Model):
    class Meta:
        verbose_name = u'57. Android手机信息'
        verbose_name_plural = u'57. Android手机信息'
        db_table = 'api_android'
        app_label = 'api'

    user = models.OneToOneField(User)
    last_notified = models.DateTimeField(auto_now=True)
    created_time = models.DateTimeField(auto_now_add=True)
    version = models.CharField(max_length=20, default='0.0.0')

    def __unicode__(self):
        return u"Android %s" % unicode(self.user)


class iOsDevice(models.Model):
    """
    和用户无关，不登陆也可能有iOsDevice的信息
    """

    class Meta:
        verbose_name = u'50. iOs手机信息'
        verbose_name_plural = u'50. iOs手机信息'
        db_table = 'api_iosdevice'
        app_label = 'api'

    udid = models.CharField(blank=False, max_length=64, unique=True, db_index=True)
    last_notified = models.DateTimeField(auto_now=True)
    is_dist = models.BooleanField(default=True)
    is_failed = models.BooleanField(default=False)
    # 如果push失败次数达到达到一定的threshold, 则停止push操作
    failed_times = models.IntegerField(default=0)

    # 版本号，push时有时候需要区分
    version = models.CharField(max_length=20, default='0.0.0')
    last_view = models.DateTimeField(default=DEFAULT_LAST_VIEW_DATETIME)
    created_time = models.DateTimeField(help_text=u"创建时间", default=DEFAULT_LAST_VIEW_DATETIME)

    def __unicode__(self):
        return u"iOs Device %s" % self.udid


class iPhone(models.Model):
    """
    Represents an iPhone used to push

    udid - the iPhone Unique Push Identifier (64 chars of hex)
    last_notified - when was a notification last sent to the phone
    is_dist - is this a phone that has dist app installed on
    """

    class Meta:
        verbose_name = u'51. 用户手机信息'
        verbose_name_plural = u'51. 用户手机信息'
        db_table = 'api_iphone'
        app_label = 'api'

    user = models.OneToOneField(User)
    udid = models.CharField(blank=True, max_length=64, unique=True)
    is_dist = models.BooleanField(default=True)  # # 除了测试版, 其他的应该都是True

    last_notified = models.DateTimeField(auto_now=True)
    created_time = models.DateTimeField(auto_now_add=True)

    # 版本号，push时有时候需要区分
    version = models.CharField(max_length=20, default='0.0.0')

    def __unicode__(self):
        return u"iPhone %s" % self.udid


class RecommendApp(models.Model):
    class Meta:
        verbose_name = u'精品应用'
        verbose_name_plural = u'精品应用'
        app_label = 'api'

    appid = models.CharField(max_length=64, verbose_name=u'应用标识')
    icon = ImgUrlField(img_type=IMG_TYPE.RECOMMENDAPP, max_length=300, verbose_name=u'应用图标')
    title = models.CharField(max_length=64, verbose_name=u'应用名称')
    description = models.CharField(max_length=300, verbose_name=u'应用描述')
    download_link = models.CharField(max_length=300, verbose_name=u'下载链接')
    callback = models.CharField(max_length=300, verbose_name=u'回调URL', default='')
    platform = models.CharField(choices=PLATFORM_CHOICES, default=PLATFORM_CHOICES.ANDROID, max_length=20,
                                verbose_name=u'平台类型')
    is_online = models.BooleanField(default=False, help_text=u"是否上线", verbose_name=u"上线")
    version = models.CharField(max_length=20, default='0.0.0')

    def as_dict(self):
        result = to_dict(self, excludes=['callback', 'platform', 'is_online', 'version'])
        return result


class AppStat(models.Model):
    class Meta:
        verbose_name = u'换量统计'
        verbose_name_plural = u'换量统计'
        db_table = 'api_appstat'
        app_label = 'api'

    user = models.ForeignKey(User, null=True, blank=True, related_name="app_user", verbose_name=u"点击用户")
    recommend_app = models.ForeignKey(RecommendApp, related_name=u"recommend_app", verbose_name=u"推荐应用")
    accept_time = models.DateTimeField(auto_now_add=True, verbose_name=u'接收时间')
    active_time = models.DateTimeField(default=None, null=True, blank=True, verbose_name=u'激活时间')


class SearchKeyword(models.Model):
    class Meta:
        verbose_name = u'搜索关键字'
        verbose_name_plural = u'搜索关键字'
        db_table = 'api_searchkeyword'
        app_label = 'api'

    keyword = models.CharField(max_length=20, help_text=u'关键字')
    is_online = models.BooleanField(default=True, help_text=u'是否上线')
    rank = models.IntegerField(max_length=10, help_text=u'排序')
    type = models.CharField(max_length=8, choices=SEARCH_KEYWORDS_TYPE, default=SEARCH_KEYWORDS_TYPE.DEFAULT)
    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')
    position = models.IntegerField(max_length=10, choices=SEARCH_KEYWORDS_POSITION, default=SEARCH_KEYWORDS_POSITION.DEFAULT)
    is_special = models.BooleanField(u'特殊样式', default=False)
    jump_type = models.CharField(u'跳转类型', max_length=3, choices=HOT_SEARCH_JUMP_TYPE, default=HOT_SEARCH_JUMP_TYPE.NORMAL)
    jump_target = models.CharField(u'跳转', max_length=300, default='')
    img_url = models.CharField(verbose_name=u'图片url', max_length=255, null=False)
    aggregate_id = models.CharField(verbose_name=u'聚合页id', max_length=255, null=False)

    explicit_word = models.CharField(max_length=20, help_text=u'外显词', default='')
    start_time = models.DateTimeField(null=False, verbose_name='生效时间')
    end_time = models.DateTimeField(null=False, verbose_name='失效时间')


class SearchKeywordOperationRecord(models.Model):
    class Meta:
        db_table = 'api_searchkeyword_operationrecord'
        app_label = 'api'
        verbose_name = '默认搜索词配置操作记录表'
    searchkeyword = models.ForeignKey(SearchKeyword, verbose_name='关联搜索关键字')
    operate_user = models.ForeignKey(User, verbose_name=u'操作对象')
    content = models.TextField(verbose_name=u'操作内容', default='')
    operate_time = models.DateTimeField(auto_now_add=True, verbose_name=u'操作时间')


class UserBlackList(models.Model):
    class Meta:
        verbose_name = u'60. 用户黑名单'
        verbose_name_plural = u'60. 用户黑名单'
        db_table = 'api_userblacklist'
        app_label = 'api'

    # 延迟导入，避免循环依赖
    from statistic.models import Device

    user = models.CharField(max_length=11, null=True, blank=True, default='', help_text=u"手机号", verbose_name=u"手机号")
    bind_user = models.ForeignKey(User, null=True, blank=True, default=None, verbose_name=u"绑定用户")
    device = models.ForeignKey(Device, null=True, blank=True, default=None, verbose_name=u'设备号')
    reason = models.CharField(choices=BLOCK_USER_REASON,
                              default=BLOCK_USER_REASON.ad,
                              max_length=1,
                              help_text=u'屏蔽原因',
                              verbose_name=u'屏蔽原因')
    add_time = models.DateTimeField(auto_now_add=True, verbose_name=u'添加时间')

    @classmethod
    def delete_by_user_id(cls, user_id):
        # UserBlackList.objects.filter(Q(bind_user_id=obj['key']) | Q(device__user__id=obj['key'])).delete()
        UserBlackList.objects.filter(bind_user_id=user_id).delete()

        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return

        device_ids = user.devices.values_list('id', flat=True)
        if not device_ids:
            return

        UserBlackList.objects.filter(device_id__in=device_ids).delete()

    @classmethod
    def user_in_black_list(cls, user_id):
        id_in_black = cls.objects.filter(bind_user_id=user_id).exists()
        if id_in_black:
            return True
        else:
            username = User.objects.get(id=user_id)._get_full_field_content_('username')
            username_in_black = username in cls.objects.values_list('user', flat=True)
            return username_in_black

    @classmethod
    def device_in_black_list(cls, device_id, platform, idfv=None):
        if device_id in settings.EXCEPT_BLACK_LIST:
            return False

        l_platform = platform.lower()
        if l_platform == 'android':
            return cls.objects.filter(device__device_id=device_id, device__platform=l_platform).exists()
        else:
            return cls.objects.filter(device__device_id=device_id, device__idfv=idfv).exists()


class PreBlackList(models.Model):
    class Meta:
        verbose_name = u'待拉黑表'
        verbose_name_plural = u'待拉黑表'
        db_table = 'api_preblacklist'
        app_label = 'api'

    report_user = models.ForeignKey(User, verbose_name=u'举报人', related_name='pre_report_user')
    reported_user = models.ForeignKey(User, verbose_name=u'被举报人', related_name='pre_reported_user')
    report_time = models.DateTimeField(verbose_name=u'最后被举报时间')


class UserProvincePermission(models.Model):
    class Meta:
        verbose_name = u'用户省份权限'
        verbose_name_plural = u'用户省份权限'
        db_table = 'api_userprovincepermission'
        app_label = 'api'

    user = models.ForeignKey(User)
    province = models.ForeignKey(Province)
    created_time = models.DateTimeField(verbose_name=u'权限时间', auto_now_add=True)

    def __unicode__(self):
        return "%s:%s" % (self.user.username, self.province.name)


class WebSlide(models.Model):
    class Meta:
        verbose_name = u'Web 轮播图'
        verbose_name_plural = u'Web 轮播图'
        app_label = 'api'

    title = models.CharField(max_length=50, blank=True, verbose_name=u'标题')
    url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=u'跳转的网址')
    image = ImgUrlField(img_type=IMG_TYPE.WEBSLIDE, max_length=1024, null=False, blank=False, verbose_name=u'轮播图片')
    ordering = models.IntegerField(default=20, verbose_name=u"展示顺序", help_text=u"小的排在前，大的排在后")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name=u'添加时间')
    effect_time = models.DateTimeField(null=True, verbose_name=u'生效时间', auto_now_add=True)
    is_online = models.BooleanField(default=True, help_text=u"是否上线", verbose_name=u"上线")

    def web_slide_data(self):
        result = {'id': self.id,
                  'url': self.url,
                  'slide_img': self.image}
        return result


class Image(models.Model):
    class Meta:
        app_label = 'api'

    url = models.URLField(verbose_name=u'图片地址')
    height = models.IntegerField()
    width = models.IntegerField()


class DeviceRecord(models.Model):
    class Meta:
        verbose_name = u'设备记录'
        verbose_name_plural = u'设备记录'
        unique_together = ("device_id", "platform")
        app_label = 'api'

    device_id = models.CharField(max_length=100, verbose_name=u'设备ID', db_index=True)
    platform = models.CharField(choices=PLATFORM_CHOICES, default=PLATFORM_CHOICES.ANDROID, max_length=20,
                                verbose_name=u'设备类型')
    user = models.ManyToManyField(User, related_name="device_record_users")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name=u"创建时间")


class Link(models.Model):
    class Meta:
        app_label = 'api'

    url = models.CharField(max_length=200, verbose_name=u"原始的URL")
    short = models.CharField(max_length=10, unique=True, verbose_name=u"缩写参数")
    description = models.CharField(max_length=200, null=True, blank=True, verbose_name=u"URL描述")

    count = models.IntegerField(default=0, verbose_name=u"访问次数")

    def __unicode__(self):
        return self.url

    def short_url(self):
        s = u'http://www.wanmeizhensuo.com/api/links/%s/' % self.short
        return u"<a href=\"%s\">%s</a>" % (s, s)

    short_url.allow_tags = True


coupon_gift_pool = redis.ConnectionPool(**settings.REDIS['coupon_gift'])


class RedisClient(object):
    prefix = ""
    pool = None

    def __init__(self):
        self.client = redis.Redis(connection_pool=self.pool)

    def _get_key(self, key):
        return self.prefix + ":" + str(key)

    def increase(self, key):
        key = self._get_key(key)
        self.client.incr(key)

    def get(self, key):
        key = self._get_key(key)
        return self.client.get(key)


class GiftClient(RedisClient):
    prefix = 'coupon_gift'
    pool = coupon_gift_pool

    def push(self, key, gift_list):
        key = self._get_key(key)
        self.client.lpush(key, *gift_list)

    def pop(self, key):
        result = None
        key = self._get_key(key)
        try:
            result = self.client.lpop(key)
            if result:
                result = json.loads(result)
        except redis.RedisError:
            result = None
        return result

    def length(self, key):
        key = self._get_key(key)
        return self.client.llen(key)

    def clear(self, key):
        key = self._get_key(key)
        self.client.delete(key)


class CouponCondTagsClient(RedisClient):
    prefix = 'coupon_condition_tags'
    pool = coupon_gift_pool

    def get(self, coupon_id):
        key = self._get_key(coupon_id)
        result = self.client.get(key)
        if result:
            return json.loads(result)
        else:
            return []

    def set(self, coupon_id, tagid_list):
        key = self._get_key(coupon_id)
        self.client.set(key, json.dumps(tagid_list))


class UserCouponsClient(RedisClient):
    prefix = 'user_coupons'
    pool = coupon_gift_pool

    def get(self, user_id):
        key = self._get_key(user_id)
        result = self.client.get(key)
        if result:
            return json.loads(result)
        else:
            return []

    def set(self, user_id, user_coupons):
        key = self._get_key(user_id)
        self.client.set(key, json.dumps(user_coupons))


class UserCheckinLog(models.Model):
    class Meta:
        verbose_name = u'签到记录'
        verbose_name_plural = u'签到记录'
        db_table = 'api_usercheckinlog'
        app_label = 'api'

    user = models.ForeignKey(User, verbose_name=u'用户', related_name='user_checkinlog', db_index=True)
    create_time = models.DateTimeField(verbose_name=u'时间', auto_now_add=True)

    @classmethod
    def get_yesterday_checked_today_not_checked_user_ids(cls):
        today = datetime.date.today()
        yesterday = today + datetime.timedelta(-1)
        _y_users = set(cls.objects.filter(create_time__range=(yesterday, today)).values_list('user_id', flat=True))
        _d_users = set(cls.objects.filter(create_time__gt=today).values_list('user_id', flat=True))

        _d = _y_users - _d_users

        return list(_d)

    @classmethod
    def get_checkin_result(cls, user):
        today = datetime.date.today()
        current_day = today.day
        current_month = today.month
        current_year = today.year
        days_of_month = calendar.monthrange(current_year, current_month)[1]

        logs = cls.objects.filter(user=user, create_time__year=current_year, create_time__month=current_month).values_list('create_time', flat=True)
        checkin_days = [day.day for day in logs]
        is_checked_today = True if current_day in checkin_days else False

        # 未签到会改变checkin_days的值
        sustain_count = _get_sustain_checkin_counts(checkin_days, is_checked_today=is_checked_today)

        # 处理美分
        checkin_points_result = _get_checkin_points_result(sustain_count, current_day, days_of_month)

        # check in
        growth_value = 0
        if not is_checked_today:
            cls.objects.create(user=user)

            # 处理加分
            if checkin_points_result[0] != 0:
                p = checkin_points_result[0]
                point.add(user_id=user.id, reason=POINTS_TYPE.SIGN_IN, point=p, is_new_sign_in=True)

            # 处理用户成长值
            event_data = send_event_task(user_id=user.id, event_type=EventType.CHECKIN)
            growth_value = event_data['growth_value']

        get_points_days = point.get_user_current_month_sign_day(user_id=user.id)
        days = []
        for day in range(1, days_of_month + 1):
            _data = {
                "day_of_month": day,
                "day_of_week": calendar.weekday(current_year, current_month, day) + 1,
                "is_checked": False,
                "got_gift": False,
                "have_gift": False,
            }
            if day in checkin_days:
                _data['is_checked'] = True

            if day in get_points_days:
                _data['got_gift'] = True

            days.append(_data)

        for index, _result in enumerate(checkin_points_result):
            days[current_day + index - 1]['have_gift'] = bool(_result)

        # 今日gift在上面checkin动作时已经领了，所以update今日的have_gift 为false
        days[current_day - 1]['have_gift'] = False

        current_day_points = checkin_points_result[0]

        # 跳转个人用户等级页
        gm_protocol = GmProtocol(api_host=settings.BACKEND_API_HOST+'/')
        return {
            'growth_value': growth_value,
            'points': current_day_points,
            'check_in_days': sustain_count,
            'is_checked_today': is_checked_today,
            'days': days,
            'url': gm_protocol.get_user_rights(user.id),
        }

    @classmethod
    def is_checked_today(cls, user):
        today = datetime.date.today()
        today_init = datetime.datetime(today.year, today.month, today.day, 0, 0, 0)

        is_checked_today = cls.objects.filter(user=user, create_time__gte=today_init).exists()
        return is_checked_today


def _get_sustain_checkin_counts(checkin_days, is_checked_today=True):
    current_day = datetime.date.today().day
    if not is_checked_today:
        checkin_days.append(current_day)

    days = [(lambda i: 1 if i in checkin_days else 0)(i) for i in range(1, current_day + 1)]
    _sum = 0

    for i in reversed(days):
        if i == 1:
            _sum += 1
        else:
            break

    return _get_real_sum(_sum)


def _get_real_sum(sum):
    if sum < 16:
        return sum
    else:
        return _get_real_sum(sum - 15)


def _get_checkin_points_result(sustain_count, current_day, days_of_month):
    # 连续签到第3天奖励50美分，连续签到第7天奖励100美分，连续签到第10天奖励200美分，连续签到第15天奖励300美分
    points_value_list = [0, 0, 0, 50, 0, 0, 0, 100, 0, 0, 200, 0, 0, 0, 0, 300]

    return points_value_list[sustain_count:][: days_of_month - current_day + 1]


def _get_checkin_growth_value_result(user_id):
    value = EventDispatcher.sent_check_in_signal(user_id)
    return value


class SearchKeywordDefault(object):
    """
       搜索框默认搜索词配置
    """
    RKEY_PREFIX = 'searchkeyword_default'

    DEFAULT_DEPLOY = {
        'searchkeyword_default': ''
    }

    @classmethod
    def _gen_key(cls):
        return cls.RKEY_PREFIX

    @classmethod
    def get(cls):
        rkey = cls._gen_key()
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_DEPLOY
            else:
                res = json.loads(res)
            return res
        except:
            return cls.DEFAULT_DEPLOY

    @classmethod
    def set(cls, deploy_info):
        rkey = cls._gen_key()
        res = deploy_info
        gadget_cache.set(rkey, json.dumps(res))


class SearchKeywordRecommend(object):
    """
       搜索框默认搜索词配置
    """
    RKEY_PREFIX = 'searchkeyword_recommend'

    DEFAULT_DEPLOY = []

    @classmethod
    def _gen_key(cls):
        return cls.RKEY_PREFIX

    @classmethod
    def get(cls):
        rkey = cls._gen_key()
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_DEPLOY
            else:
                res = json.loads(res)
            return res
        except:
            return cls.DEFAULT_DEPLOY

    @classmethod
    def set(cls, deploy_info):
        rkey = cls._gen_key()
        res = deploy_info
        gadget_cache.set(rkey, json.dumps(res))
