# -*- coding:utf-8 -*-
"""后台管理处理"""

from kyger.utility import json2dict, numeric, html_escape, date, dict2json_file
from kyger.parser_ini import Config


class User(object):
    synch_login = False  # 同一帐号是否允许同时登录
    __page = 0  # 当前页
    __total_page = 0  # 总页数
    __total_rows = 0  # 总记录数

    def __init__(self, db=None, kg=None):
        # 数据库
        self.db = db
        self.kg = kg

        # 语言包
        import importlib
        web = self.db.list(table='web', where=self.kg['web']['id'], shift=1)
        user = importlib.import_module('language.frontend.%s.user' % web['language'])
        self.lang = user.package

    def get(self, id=0, username='', phone='', email=''):
        """
        获取会员信息, [id|username|phone|email] 最少有一个参数
        同时追加用户组信息 += {"rank_name": "", "discount": 0.00}
        :param id: [int]  会员ID
        :param username: 用户名
        :param phone: 手机号
        :param email: email
        :return: {}
        """
        # 获取rank表数据
        user_rank = self.db.list(
            table='rank',
            where='webid = %s && enable = 1' % self.kg['web']['id']
        )
        # 获取用户数据
        if isinstance(id, int) and id > 0:
            r = self.db.list('user', '*', "id = %s" % id, limit=1, shift=1)
        elif username:
            r = self.db.list('user', '*', '`username` = "%s"' % username, limit=1, shift=1)
        elif phone:
            r = self.db.list('user', '*', '`phone` = "%s"' % phone, limit=1, shift=1)
        elif email:
            r = self.db.list('user', '*', '`email` = "%s"' % email, limit=1, shift=1)
        else:
            r = {}
        if r.get("level", False):
            for row in user_rank:
                if row['id'] in json2dict(r['level']):
                    r['rank_name'] = row['rankname']
                    r['discount'] = row['discount']
        if r:
            r = self.data_format(r, '%Y-%m-%d %H:%M:%S')
        return r

    def update(self, id=0, data={}):
        """
        创建管理员
        :param id: 用户id, 为0时创建用户, 其它数值时修改用户
        :param data: 创建用户的数据
        :return 1: {'state': 'SUCCESS', 'id': 7} 成功返回ID
        :return 2: {'state': 'FAILURE', 'msg': ''} 失败返回错误消息
        :Example: r = admin(self.db).add(username='admin',password='123456')
        """
        from kyger.utility import is_format, str_random, md5, ip2address
        test = (data.get('username', None), data.get('password', None), data.get('phone', ''), data.get('email', ''))
        username, password, phone, email = test
        # 帐号合法性检测
        config = Config('config/settings.ini').get('user')
        if config['username_strictly'] == 1:  # 判断是否严格检测用户名
            if username and not is_format(username, 'username'): return {'state': 'FAILURE', 'msg': self.lang['add'][0]}
        if username in config['disable'].split(','): return {'state': 'FAILURE', 'msg': self.lang['add'][0]}

        if id:
            if len(password) < 5 and password: return {'state': 'FAILURE', 'msg': self.lang['add'][1]}
        else:
            if len(password) < 5: return {'state': 'FAILURE', 'msg': self.lang['add'][1]}

        if phone and not is_format(phone, 'phone'): return {'state': 'FAILURE', 'msg': self.lang['add'][2]}
        if email and not is_format(email): return {'state': 'FAILURE', 'msg': self.lang['add'][3]}
        if not (username or phone or email): return {'state': 'FAILURE', 'msg': self.lang['add'][4]}  # 必须填写一个

        # 帐号是否可用检测
        user = self.get(username=username)
        if username and user and user.get('id', '-') != id: return {'state': 'FAILURE', 'msg': self.lang['add'][5]}
        user = self.get(phone=phone)
        if phone and user and user.get('id', '-') != id: return {'state': 'FAILURE', 'msg': self.lang['add'][6]}
        user = self.get(email=email)
        if email and user and user.get('id', '-') != id: return {'state': 'FAILURE', 'msg': self.lang['add'][7]}

        encryption = str_random(8)
        password_md5 = md5('%s%s' % (md5(password), md5(encryption))) if password else ''
        data = {
            'username': username,
            'email': email,
            'image': data.get('image', ''),
            'qq': data.get('qq', '').strip(),
            'problem': html_escape(data.get('problem', '')),
            'answer': html_escape(data.get('anwer', '')),
            'companyname': html_escape(data.get('companyname', '')),
            'level': json2dict(data.get('level', [1])),
            'companyweb': html_escape(data.get('companyweb', '')),
            'companyaddress': html_escape(data.get('companyaddress', '')),
            'audit': numeric(data.get('audit', 0), 0, 2),
            'type': numeric(data.get('type', 0), 0, 1),
            'sex': numeric(data.get('sex', 2), 0, 2),
            'money': numeric(data.get('money', 0)),
            'usemoney': numeric(data.get('usemoney', 0)),
            'scores': numeric(data.get('scores', 0), 0),
            'nickname': html_escape(data.get('nickname', '')),
            'phone': phone,
            'fax': html_escape(data.get('fax', '')),
            'frequency': numeric(data.get('frequency', 0), 0),
            'joinip': html_escape(data.get('joinip', '')),
            'effective': numeric(data.get('effective', 0), 0, 1),
        }
        if id:  # 修改管理员
            if password: data.update({'password': password_md5, 'encryption': encryption})
            row = self.db.edit('user', data, where=id)
            user_id = id if row else 0
        else:  # 添加管理员
            # ip地址
            data['openid'] = self.kg['session'].get('openid', '')
            ip_data = ip2address(self.db, data['joinip']) if ip2address(self.db, data['joinip']) else {}
            data['joinaddress'] = ip_data.get('province', '') + ip_data.get('city', '')
            data.update({'password': password_md5, 'encryption': encryption})
            data['jointime'] = int(self.kg['run_start_time'][1])  # 创建时间
            user_id = self.db.add('user', data)
        if isinstance(user_id, int) and user_id > 0:
            return {'state': 'SUCCESS', 'id': user_id}
        else:
            return {'state': 'FAILURE', 'msg': self.lang['add'][8]}

    def login(self, uid, password):
        """
        管理员登录
        :param uid: [username|phone|email] 登录帐号
        :param password: 登录密码
        :return: {'state': 'SUCCESS', 'id': id, 'loginid': uid}  成功返回 id 及登录帐号
                {'state': 'FAILURE', 'loginid': uid, 'msg': ''}  失败返回消息及登录帐号
        """
        from kyger.utility import md5
        field = self.uid_type(uid)

        if field:
            r = self.db.list(table='user', where='`%s` = "%s"' % (field, uid), limit=1, shift=1)
            id = r.get('id', 0)
            if isinstance(id, int) and id > 0:
                if r['password'] == md5('%s%s' % (md5(password), md5(r['encryption']))):  # 登录成功
                    if 0 == r['audit'] == 0:  # 检测帐号是否审核
                        if r['effective']:  # 检测帐号是否被禁用
                            self.db.edit('user', {'frequency': r['frequency'] + 1}, id, 1, False)  # 登录次数+1
                            # 成功登录, 需要返回登录次数, 作同一帐号异常登录比较
                            info = {'state': 'SUCCESS', 'id': id, 'loginid': uid, 'frequency': r['frequency'] + 1}
                        else:
                            info = {'state': 'FAILURE', 'loginid': uid, 'msg': self.lang['log'][4]}  # 禁止登录
                    else:
                        info = {'state': 'FAILURE', 'loginid': uid, 'msg': self.lang['log'][3]}  # 未审核
                else:
                    info = {'state': 'FAILURE', 'loginid': uid, 'msg': self.lang['log'][0]}  # 密码错误
            else:
                info = {'state': 'FAILURE', 'loginid': uid, 'msg': self.lang['log'][1]}  # 用户不存在
        else:
            info = {'state': 'FAILURE', 'loginid': uid, 'msg': self.lang['log'][2]}  # 帐号类型不正确

        return info

    def login_freq(self, uid=None, ip=None, minute=30):
        """
        检测用户在指定的时间内登录次数, 默认统计同一登录帐号, 设置IP时统计同一IP错误次数
        只统计登录错误和登录失败的次数
        :param uid: 用户帐号
        :param minute: 距当前时间多少分钟内
        :param ip: IP地址, 默认使用用户ID统计
        :return: [int]
        """
        import time
        t = time.time() - minute * 60
        if uid:
            wh = '`type` =11 && info->"$.state" = "FAILURE" && `info`->"$.loginid" = "%s" && `addtime` > %s' % (uid, t)
        elif ip:
            wh = '`type` =11 && info->"$.state" = "FAILURE" && `ip` = "%s" && `addtime` > %s' % (ip, t)
        else:
            return 999
        r = self.db.list('log', 'count(`id`) as count', wh, shift=1, limit=1)
        return r['count']

    def uid_type(self, uid):
        """
        获取用户登录帐号类型: username|phone|email|None
        :param uid: 登录帐号
        :return: [str] username|phone|email|None
        """
        from kyger.utility import is_format
        if is_format(uid, 'phone'):
            field = 'phone'
        elif is_format(uid):
            field = 'email'
        elif is_format(uid, 'username'):
            field = 'username'
        else:
            field = None
        return field

    def get_role(self, id):
        """
        获取角色信息
        :param id: 角色id
        :return: {}
        """
        return self.db.list("role", where=id, shift=1)

    def list_page(self, *args, **kwargs):
        """
        分页获取用信息，参数同list。
        :return:{
            'list':          # 分页的当前页用户数据
            'page_html':     # 分页的html模板
            'page_data':     # 分页的数据：当前页、总页数、总记录数
        }
        """
        # page和row的数据
        self.__page = numeric(self.kg['get'].get('page', 1), 1)  # 当前页
        if 'row' in kwargs:
            row = kwargs['row']  # 在kwargs里
        elif len(args) > 2:
            row = args[1]  # 在args里
        else:
            row = 10  # 默认10

        # 获取用户数据
        data = self.list(*args, **kwargs)
        # 分页模板合成
        web_url = self.kg['server'].get('WEB_URL')
        from kyger.common import page_tpl
        page_html = page_tpl(self.__page, self.__total_page, row, web_url)  # 获取分页模板
        self.__total_rows = self.db.total_rows  # 总记录数
        self.__total_page = self.db.total_page  # 总页数
        return {
            'list': data,
            'page_html': page_html,
            'page_data': {'page': self.__page, 'total_page': self.__total_page, 'total_rows': self.__total_rows}
        }

    def list(self, row=10, sort=0, level=0, type=0, audit=0, effective=0, word='', date_format='%Y-%m-%d'):
        """
        获取用户数据
        :param row: [int] 分页时为每页要显示的数量，不分页时为调用的总记录数。缺省值为 10
        :param sort: [int] 排序，,0ID降序，1ID升序，2帐户金钱降序、3帐户金钱升序、4帐户积分降序、5帐户积分升序、6已消费金钱降序、7已消费金钱升序、8登录次数降序、9登录次数升序，缺省值为0
        :param level: [int] 会员等级ID，0为所有等级，缺省值为0
        :param type: [int] 0所有类型、1个人会员、2企业会员，缺省值为0
        :param audit: [int] 0所有状态的会员、1已验证的会员、2未验证的会员，缺省值为0
        :param effective: [int] 0所有状态的会员、1允许登录的会员、2禁止登录的会员，缺省值为0
        :param word: [str] 搜索关键字，缺省值空
        :param date_format: [str] 日期格式化：
                                %y 两位数的年份表示（00-99）  %Y 四位数的年份表示（000-9999）  %m 月份（01-12）  %d 日，月内中的一天（0-31）
                                %H 24小时制小时数（0-23）  %I 12小时制小时数（01-12）  %M 分钟数（00=59）  %S 秒（00-59）
                                %a 本地简化星期名称  %A 本地完整星期名称 %b 本地简化的月份名称, 英文  %B 本地完整的月份名称, 英文
                                %c 本地相应的日期表示和时间表示  %j 年内的一天（001-366）  %p 本地A.M.或P.M.的等价符  %U 一年中的星期数（00-53）星期天为星期的开始（第n周）
                                %w 星期（0-6），星期天为星期的开始  %W 一年中的星期数（00-53）星期一为星期的开始（第n周）   %x 本地相应的日期表示
                                %X 本地相应的时间表示  %Z 当前时区的名称  %% %号本身
        """
        # where
        level_sql = " && `level` rlike '[\[|, ]%d[\]|,]'" % level if level else ''
        type_sql = ' && type=%s' % (type - 1) if type > 0 else ''
        audit_sql = ' && audit=%s' % (audit - 1) if audit > 0 else ''
        effective_sql = ' && effective=%s' % (effective - 1) if effective > 0 else ''
        word_sql = ' && username like "%%%s%%"' % word if word else ''
        where = '1%s%s%s%s%s' % (level_sql, type_sql, audit_sql, effective_sql, word_sql)

        # sort
        sort_list = {
            0: 'id DESC',
            1: 'id ASC',
            2: 'money ASC',
            3: 'money DESC',
            4: 'scores DESC',
            5: 'scores ASC',
            6: 'usemoney DESC',
            7: 'usemoney ASC',
            8: 'frequency DESC',
            9: 'frequency ASC'
        }
        # limit
        limit = row if self.__page else '0,%s' % row

        data = self.db.list(
            table='user',
            where=where,
            order=sort_list[sort],
            page=self.__page,
            limit=limit
        )
        # 判断是否超过最大页
        if self.__page > self.db.total_page:
            self.__page = self.db.total_page
            data = self.db.list(
                table='user',
                where=where,
                order=sort_list[sort],
                page=self.__page,
                limit=limit
            )
        data = self.data_format(data, date_format) if data else []
        return data

    def data_format(self, data, date_format):
        """
        将数据进行整形
        :param data: [list{}] 从数据库查出的数据
        :param date_format: [str] 日期格式化：
                                %y 两位数的年份表示（00-99）  %Y 四位数的年份表示（000-9999）  %m 月份（01-12）  %d 日，月内中的一天（0-31）
                                %H 24小时制小时数（0-23）  %I 12小时制小时数（01-12）  %M 分钟数（00=59）  %S 秒（00-59）
                                %a 本地简化星期名称  %A 本地完整星期名称 %b 本地简化的月份名称, 英文  %B 本地完整的月份名称, 英文
                                %c 本地相应的日期表示和时间表示  %j 年内的一天（001-366）  %p 本地A.M.或P.M.的等价符  %U 一年中的星期数（00-53）星期天为星期的开始（第n周）
                                %w 星期（0-6），星期天为星期的开始  %W 一年中的星期数（00-53）星期一为星期的开始（第n周）   %x 本地相应的日期表示
                                %X 本地相应的时间表示  %Z 当前时区的名称  %% %号本身
        :return: [list{}] 将整形过后的数据返回
        """
        # 数据类型判断
        if isinstance(data, dict):
            data = [data]
            act_type = 'dict'
        else:
            act_type = 'list'
        id_list = []
        for row in data:
            # 创建时间
            row['jointime'] = date(row['jointime'], date_format)
            # 转json
            row['level'] = json2dict(row['level'])
            id_list.append(str(row['id']))

        # 后两次登录时间，最后两次登录ip
        login = self.db.list(
            table='log',
            field='userid, addtime, ip',
            where='type=6 && userid in (%s)' % ','.join(id_list),
            order='addtime DESC'
        )
        res = {}
        for row in login:
            if int(row['userid']) not in res:
                res[int(row['userid'])] = [row]
            else:
                res[int(row['userid'])].append(row)
        for row in data:
            if row['id'] in res:
                login_time = date(res[row['id']][0]['addtime'], '%Y-%m-%d %H:%M:%S')
                if len(res[row['id']]) > 1:
                    row['logintime'] = [login_time, date(res[row['id']][1]['addtime'], '%Y-%m-%d %H:%M:%S')]
                    row['loginip'] = [res[row['id']][0]['ip'], res[row['id']][1]['ip']]
                else:
                    row['logintime'] = [login_time, 0]
                    row['loginip'] = [res[row['id']][0]['ip'], '']
            else:
                row['logintime'], row['loginip'] = ([0, 0], ['', ''])
        if act_type == 'dict': data = data[0]
        return data

