# -*- coding:utf-8 -*-
from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractUser
from django.db.models import Max, Count, Q
from . import utils
import random, base64
from django.core import validators
from django.urls import reverse
from django_summernote.models import AbstractAttachment
from django.db.utils import ProgrammingError, InternalError
from django.utils import timezone
from django.conf import settings

def get_usefull_port():
    try:
        max_port = User.objects.aggregate(Max('port')).get('port__max')
    except ProgrammingError:
        max_port = None
    if not max_port:
        max_port = 17236
    new_port = int(max_port) + random.randint(2, 5)
    if new_port in (24554, 60177, 60179):
        new_port += 1
    return new_port

def get_node_group():
    if hasattr(settings, 'NODE_GROUPS') and len(settings.NODE_GROUPS) > 1:
        try:
            group_ids = set()
            for g in settings.NODE_GROUPS:
                group_ids.add(g[0])
            user_group_ids = User.objects.values_list('node_group_id', flat=True).order_by().distinct()
            #print(user_group_ids.query)
            #print(set(user_group_ids))
            not_have_group = group_ids-set(user_group_ids)
            if not_have_group:
                return random.choice(tuple(not_have_group))
            user_count = User.objects.filter(Q(switch=True)&Q(is_active=True)&Q(node_group_id__in=group_ids)).values('node_group_id').annotate(n=Count('*')).order_by('n')
            #print(user_count.query)
            if user_count:
                return user_count[0].get('node_group_id', 1)
        except (ProgrammingError, InternalError):
            pass
    return 1

# 用户模型.
class User(AbstractUser):

    avatar = models.CharField(verbose_name='头像', max_length=63,default='avatar1.png')
    port = models.PositiveSmallIntegerField(verbose_name='端口',unique=True, default= get_usefull_port)
    passwd = models.CharField(verbose_name='端口密码',max_length=16,default=utils.gen_passwd)
    t = models.IntegerField(verbose_name='最后使用时间戳',default=0)
    u = models.BigIntegerField(verbose_name='上传流量',default=0)
    d = models.BigIntegerField(verbose_name='下载流量',default=0)
    transfer_enable = models.BigIntegerField(verbose_name='每月流量限额',default=settings.INIT_TRANS_ENABLE)
    switch = models.BooleanField(verbose_name='流量开关状态',default=True)
    last_check_in_time = models.DateTimeField(verbose_name='最后签到时间',null=True)
    check_in_count = models.IntegerField(verbose_name='连续签到次数',default=0)

    reg_ip = models.GenericIPAddressField(verbose_name='注册IP',unpack_ipv4=True,null=True)
    last_login_ip = models.GenericIPAddressField(verbose_name='上次登录IP',unpack_ipv4=True,null=True)
    last_login_date = models.DateTimeField(verbose_name='上次登录时间',null=True,auto_now_add=True)
    this_login_ip = models.GenericIPAddressField(verbose_name='本次登录IP',unpack_ipv4=True,null=True)
    this_login_date = models.DateTimeField(verbose_name='本次登录时间',null=True,auto_now_add=True)

    invite_num = models.IntegerField(verbose_name='可以生成邀请码的个数',default=0)
    last_gen_invite_code_time = models.DateTimeField(verbose_name='上次生成邀请码时间',null=True)

    email_validate_code = models.CharField(max_length=63,verbose_name='邮箱验证码',default=utils.gen_val_code)
    bind_email = models.BooleanField(verbose_name='是否已验证邮箱', default=False)

    wx_validate_code = models.CharField(max_length=31,verbose_name='微信公众号验证码',default=utils.gen_val_code)
    wxopenid = models.CharField(max_length=127,verbose_name='微信OPENID',null=True)

    node_group_id = models.PositiveSmallIntegerField('节点组', default=get_node_group, choices=settings.NODE_GROUPS, help_text='settings_custom.py的NODE_GROUPS字段')
    last_change_node_group_time = models.DateTimeField('最后修改节点组时间', null=True, blank=True, default=None)

    class Meta:
        verbose_name = '用户'
        verbose_name_plural = verbose_name
        ordering = ['-id']

    def __str__(self):
        return self.username

#节点模型
class AbstractNode(models.Model):
    METHOD_CHOICES = (
        ('rc4-md5', 'rc4-md5'),
        ('chacha20', 'chacha20'),
        ('aes-256-cfb', 'aes-256-cfb'),
        ('aes-192-cfb', 'aes-192-cfb'),
        ('aes-128-cfb', 'aes-128-cfb'),
        ('salsa20', 'salsa20'),
        ('rc4', 'rc4'),
        ('table', 'table'),
    )

    STATUS_CHOICES = (
        ('ON-LINE','正常'),
        ('OFF-LINE','离线'),
        ('BANDWIDTH-OVER','流量用完'),
        ('ATTACKED','被攻击中'),
        ('INIT','初始化中'),
        ('MAINTAIN','维护中'),
        ('OUT','下线'),
    )
    name = models.CharField(max_length=63,verbose_name='节点名称')
    location = models.CharField(max_length=127, verbose_name='节点地理位置')
    flag = models.CharField(max_length=63, verbose_name='节点国旗图标', blank=True, default=None, help_text='us：美国；jp：日本；hk：香港；sg：新加坡；cn：中国；kr：韩国；gb：英国；参考：http://flag-icon-css.lip.is/')
    ip = models.GenericIPAddressField(verbose_name='节点IP地址',protocol='IPv4')
    ipv6 = models.GenericIPAddressField(blank=True, null= True , protocol='IPv6', verbose_name='节点IPv6地址')
    method = models.CharField(choices=METHOD_CHOICES,max_length=63, default='chacha20', verbose_name='节点加密方式')
    info = models.TextField(max_length=255, verbose_name='节点信息')
    status = models.CharField(max_length=63, choices=STATUS_CHOICES,default='INIT', verbose_name='节点状态')
    traffic_rate = models.PositiveIntegerField(verbose_name='流量倍率百分比',help_text='100表示默认1倍', default=100)
    sort = models.SmallIntegerField(verbose_name='排序', default=0, help_text='小的在前面')
    remark_for_admin = models.TextField('管理员备注',null=True, blank=True, default=None)
    tags = models.ManyToManyField('NodeTag', verbose_name='标签集合', blank=True)

    #SSR属性
    ORIGIN_CHOICES = (
        ('origin','origin：原版协议'),
        ('auth_sha1_v4','auth_sha1_v4：较高安全性，有宽松的时间校对要求，混淆强度大'),
        ('auth_aes128_md5','auth_aes128_md5：最高安全性，有宽松的时间校对要求，计算量相对高一些，混淆强度较大'),
        ('auth_aes128_sha1','auth_aes128_sha1：最高安全性，有宽松的时间校对要求，计算量相对高一些，混淆强度较大'),
        ('auth_sha1_v4_compatible','auth_sha1_v4_compatible，兼容版'),
    )
    protocol = models.CharField(max_length=63,verbose_name='协议插件',default='auth_sha1_v4_compatible',choices=ORIGIN_CHOICES,help_text='协议推荐：协议用auth_aes128_md5或auth_aes128_sha1最佳（但是不支持原版SS协议），此时即使使用rc4加密亦可，混淆随意；_compatible后缀表示兼容原版SS协议')
    protocol_param = models.CharField(max_length=63,verbose_name='协议插件参数',blank=True,default='')
    OBFS_CHOICES = (
        ('plain','plain：不混淆，无参数'),
        ('tls1.2_ticket_auth','tls1.2_ticket_auth：伪装为tls请求。参数配置与http_simple一样'),
        ('http_simple','http_simple：简易伪装为http get请求'),
        ('http_post','http_post：与http_simple绝大部分相同，POST伪装方式'),
        ('tls1.2_ticket_auth_compatible','tls1.2_ticket_auth_compatible：兼容版'),
        ('http_simple_compatible','http_simple_compatible：兼容版'),
        ('http_post_compatible','http_post_compatible：兼容版'),
    )
    obfs = models.CharField(max_length=127,verbose_name='混淆插件',choices=OBFS_CHOICES,default='tls1.2_ticket_auth_compatible',
                            help_text='混淆推荐：如果QoS在你的地区明显，混淆建议在http_simple与tls1.2_ticket_auth中选择，具体选择可以通过自己的试验得出。如果选择混淆后反而变慢，那么混淆请选择plain。如果你不在乎QoS，但担心你的个人vps能不能持久使用，那么混淆选择plain或tls1.2_ticket_auth，协议选择auth_aes128_md5或auth_aes128_sha1')
    obfs_param = models.CharField(max_length=63,verbose_name='混淆插件参数',blank=True,default='')

    ssh_port = models.PositiveSmallIntegerField(verbose_name='SSH端口号',help_text='用于发送远程命令',default=22)
    last_api_request_time = models.DateTimeField(auto_now_add=True, verbose_name='最后调用远程API的时间')

    slug = models.CharField(verbose_name='API Key',unique=True, db_index=True, max_length=127, default=utils.gen_api_key, editable=False)
    api_key = models.CharField(verbose_name='API Key',unique=True,max_length=127,default=utils.gen_api_key, editable=False)
    api_secret = models.CharField(max_length=255,verbose_name='API Secret 密匙',default=utils.gen_api_secret)

    class Meta:
        abstract = True

    def __str__(self):
        return '%s[%s]'%(self.name,self.ip)


    passwd = ''
    port = ''

    @property
    def ss_url(self):
        return 'ss://%s' % (self.ss_protocol,)

    @property
    def ss_qrcode(self):
        return 'ss://%s' % (base64.encodebytes(self.ss_protocol.encode()).decode().strip(),)

    @property
    def ss_protocol(self):
        return '%s:%s@%s:%s' % (self.method, self.passwd, self.ip, self.port)

class Node(AbstractNode):
    node_group_id = models.PositiveSmallIntegerField('节点组', default=1, choices=settings.NODE_GROUPS,
                                                     help_text='settings_custom.py的NODE_GROUPS字段')
    class Meta:
        verbose_name = '节点'
        verbose_name_plural = verbose_name
        ordering = ['sort', 'id']

#节点标签模型
class NodeTag(models.Model):

    slug = models.CharField(max_length=63,verbose_name='标识', help_text='请使用字母、数字、下划线、中划线组成，不可重复', primary_key=True,
                validators= (validators.RegexValidator(r'[\w-]+'),), unique=True,)
    name = models.CharField(max_length=63, verbose_name='标签名称')

    class Meta:
        verbose_name = '节点标签'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s:%s' % (self.slug, self.name)

#邀请码模型
class InviteCode(models.Model):

    code = models.CharField(max_length=127,verbose_name='邀请码',default=utils.gen_invite_code,unique=True)
    create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
    used_time = models.DateTimeField(null=True, blank=True, verbose_name='使用时间')
    TYPE_DEFAULT = 'DEFAULT'
    TYPE_TIMING = 'TIMING'
    TYPE_USERS = 'USERS'
    TCHOICES = (
        (TYPE_DEFAULT,'默认类型'),
        (TYPE_TIMING,'定时发放类型'),
        (TYPE_USERS,'用户生成类型'),
    )
    type = models.CharField(max_length=15,verbose_name='邀请码类型',default=TYPE_DEFAULT,choices=TCHOICES)
    show_time = models.DateTimeField(null=True, blank=True, verbose_name='公开显示时间')

    create_user = models.ForeignKey(User,null=True, editable=False, verbose_name='创建者',on_delete=models.SET_NULL,related_name='created_code_set')
    used_user = models.ForeignKey(User,null=True, blank=True, verbose_name='使用者',on_delete=models.SET_NULL,related_name='used_code_set')

    traffic = models.BigIntegerField(verbose_name='流量',default=settings.INIT_TRANS_ENABLE, help_text='以最小的字节B为单位')
    enable = models.BooleanField(verbose_name='是否可用',default=True)

    class Meta:
        verbose_name = '邀请码'
        verbose_name_plural = verbose_name
        ordering = ['-id']

    def __str__(self):
        return '[%s]%s'%(self.code,'可用' if self.enable else '失效')

#站内文章模型
class Post(models.Model):
    slug = models.CharField(max_length=255,verbose_name='内容标识Slug', unique=True,
                validators= (validators.RegexValidator(r'[\w-]+'),),
                help_text='请使用字母、数字、下划线、中划线组成，不可重复')
    title = models.CharField('标题', max_length=255)
    body = models.TextField('正文')
    created_time = models.DateTimeField('创建时间',auto_now_add=True)
    last_modified_time = models.DateTimeField('修改时间',auto_now=True)
    status = models.CharField('文章状态', max_length=31, choices=(('PUBLISHED','已发布'),('DRAFT','草稿')), default='DRAFT')
    content_type = models.CharField('内容类型', max_length=31, choices=(('ANNOUNCE', '站内通告'), ('PAGE','页面'), ('OTHER', '其他类型')), default= 'ANNOUNCE')
    abstract = models.CharField('摘要', max_length=63, blank=True, null=True, help_text="可选，如若为空将摘取正文的前54个字符")
    topped = models.BooleanField('置顶', default=False)
    create_user = models.ForeignKey(User, null=True, editable=False, verbose_name='创建者', on_delete=models.SET_NULL)

    def __str__(self):
        return '%s [%s]'%(self.title, self.get_status_display())

    class Meta:
        verbose_name = '文章内容'
        verbose_name_plural = verbose_name
        ordering = ['-topped','-last_modified_time']

    def get_absolute_url(self):
        return reverse('user:post_detail', kwargs={'pk': self.pk})


#附件模型
class Attachment(AbstractAttachment):
    rename = models.BooleanField(verbose_name='是否重命名', default=True,
        help_text='如果选中，则会随机重命名；否则不会重命名，但是有覆盖已有同名文件风险。')

    class Meta:
        verbose_name = '附件'
        verbose_name_plural = verbose_name
        ordering = ['-uploaded']

#流量记录
class AbstractTrafficRecord(models.Model):
    u = models.BigIntegerField(verbose_name='上传流量', default=0)
    d = models.BigIntegerField(verbose_name='下载流量', default=0)
    create_date = models.DateField(verbose_name='产生的日期', auto_now_add=True)
    create_time = models.TimeField(verbose_name='产生的时间点', auto_now_add=True)
    rate = models.PositiveIntegerField(verbose_name='流量倍率百分比',help_text='100表示默认1倍', default=100)
    type = models.PositiveSmallIntegerField(verbose_name='类型', default=0, help_text='0:接口自动记录类型；1/2 日/月汇总数据')
    summary_date = models.DateField(verbose_name='汇总产生日期', null=True, blank=True, default=None)
    port = models.PositiveSmallIntegerField(verbose_name='端口', blank=True, default=None)

    class Meta:
        abstract = True
    def __str__(self):
        return '[%d]%s'%(self.port, self.create_time)

class TrafficRecord(AbstractTrafficRecord):
    node = models.ForeignKey(Node, null=True, verbose_name='所属节点', on_delete=models.CASCADE)
    class Meta:
        verbose_name = '流量记录'
        verbose_name_plural = verbose_name
        ordering = ['-id']

#用户动作记录
class ActionRecord(models.Model):
    type = models.CharField(verbose_name='行为类型', max_length=63)
    remark = models.TextField(verbose_name='行为备注', null=True)
    meta = models.CharField(verbose_name='一些信息', max_length=1023, null=True)
    create_time = models.DateTimeField(verbose_name='产生时间', auto_now_add=True)
    create_user = models.ForeignKey(User, null=True, editable=False, verbose_name='创建者', on_delete=models.SET_NULL)
    ip = models.CharField(verbose_name='ip地址', null=True, max_length=255)

    class Meta:
        verbose_name = '用户动作记录'
        verbose_name_plural = verbose_name
        ordering = ['-create_time']