#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import logging
import time

from django.db import transaction
from django.http import StreamingHttpResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Avg,Max,Min,Count,Sum, Q  #   引入函数

from Model.models import UIDModel, UserModel, UserUIDModel, HistoryUIDModel
from Object.RedisObject import RedisObject
from Object.ResponseObject import ResponseObject
from Object.TokenObject import TokenObject
from Service.ModelService import ModelService


class UIDView(View):

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(UIDView, self).dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        request.encoding = 'utf-8'
        request_dict = request.GET
        operation = kwargs.get('operation')
        return self.validate(request_dict, operation)

    def post(self, request, *args, **kwargs):
        request.encoding = 'utf-8'
        request_dict = request.POST
        operation = kwargs.get('operation')
        return self.validate(request_dict, operation)

    def validate(self, request_dict, operation):
        token = request_dict.get('token', None)
        response = ResponseObject()

        token = TokenObject(token)
        if token.code != 0:
            return response.json(token.code)

        if operation == 'quantity':
            return self.do_quantity(request_dict, response)
        elif operation == 'allot':
            return self.do_allot(request_dict, response)
        elif operation == 'remove':
            return self.do_remove(request_dict, response)
        elif operation == 'download':
            return self.download_txt(token, response)
        elif operation == 'download_1':
            return self.download_txt_two(token, response)
        elif operation == 'list':
            return self.do_list(request_dict, response)
        elif operation == 'delete':
            return self.do_delete(token.userID, request_dict, response)
        elif operation == 'batchDelete':
            return self.do_batch_delete(token.userID, request_dict, response)
        elif operation == 'adminUpdate':
            return self.do_admin_update(token.userID, request_dict, response)
        elif operation == 'history':
            return self.do_history(token.userID, request_dict, response)
        elif operation == 'statistics':
            return self.do_admin_statistics(token.userID, request_dict, response)
        else:
            return response.json(309)

    # 查询当前可用的UID的数量
    def do_quantity(self, request_dict, response):
        token = request_dict.get('token', None)

        token = TokenObject(token)
        if token.code != 0:
            return response.json(token.code)

        user_qs = UserModel.objects.filter(id=token.userID)
        if user_qs.exists():
            user = user_qs[0]
            if user.permission == '0':
                return self.do_admin_quantity(request_dict, response, user.username)
            else:
                return self.do_not_admin_quantity(request_dict, response, user.username)
        else:
            return response.json(9)

    # 管理员的查询UID数量操作
    def do_admin_quantity(self, request_dict, response, admin):
        datas = []
        domestic = UIDModel.objects.filter(area=0, status=0).count()
        foreign = UIDModel.objects.filter(area=1, status=0).count()
        item = {}
        item['isAdmin'] = 1
        item['domestic'] = domestic
        item['foreign'] = foreign
        item['username'] = admin
        datas.append(item)

        user_qs = UserModel.objects.filter(~Q(Q(permission='0')))
        for user in user_qs:
            item = {'isAdmin': 0}
            result = UserUIDModel.objects.filter(user__id=user.id, uid__status=1, uid__area=0).aggregate(num=Count('uid__status'))
            item['domestic'] = result['num']
            result = UserUIDModel.objects.filter(user__id=user.id, uid__status=1, uid__area=1).aggregate(num=Count('uid__status'))
            item['foreign'] = result['num']
            item['username'] = user.username
            datas.append(item)

        return response.json(0, {'data': datas})

    # 非管理员的查询UID数量操作
    def do_not_admin_quantity(self, request_dict, response, username):
        user_qs = UserModel.objects.filter(username=username)
        if user_qs.exists():
            user = user_qs[0]
            datas = []
            item = {'isAdmin': 0}
            result = UserUIDModel.objects.filter(user__id=user.id, uid__status=1, uid__area=0).aggregate(num=Count('uid__status'))
            item['domestic'] = result['num']
            result = UserUIDModel.objects.filter(user__id=user.id, uid__status=1, uid__area=1).aggregate(num=Count('uid__status'))
            item['foreign'] = result['num']
            item['username'] = user.username
            datas.append(item)
            return response.json(0, {'data': datas})
        else:
            return response.json(444)

    # 分配UID
    @transaction.atomic
    def do_allot(self, request_dict, response):
        username = request_dict.get('username', None)
        quantity = int(request_dict.get('quantity', None))
        area = request_dict.get('area', None)
        token = request_dict.get('token', None)

        token = TokenObject(token)
        if token.code != 0:
            return response.json(token.code)
        user = UserModel.objects.get(id=token.userID)

        if not user or '0' not in user.permission:
            return response.json(404)

        # 要分配的对象
        allot_user_qs = UserModel.objects.filter(username=username)
        if not allot_user_qs.exists():
            return response.json(444, 'username')

        # 取出对应区域可用的UID分配给allot_user
        uid_qs = UIDModel.objects.filter(area=area, status=0)
        count = uid_qs.count()
        if count < quantity:
            return response.json(444, '设备UID不足')

        updates = []
        datas = []
        count = 0
        if uid_qs.exists():
            uid_qs = uid_qs[0:quantity]
            now_time = int(time.time())
            savePoint = transaction.savepoint()
            for item in uid_qs:
                item.status = 1
                item.update_time = time.time()
                user_uid = UserUIDModel()
                user_uid.uid = item
                user_uid.user = allot_user_qs[0]
                user_uid.add_time = now_time
                user_uid.update_time = now_time
                datas.append(user_uid)
                updates.append(item)

                if len(datas) % 5000 == 0:
                    result = self.do_update(datas, updates, savePoint)
                    if result != 0:
                        return response.json(result)

            if len(datas) > 0:
                result = self.do_update(datas, updates, savePoint)
                if result != 0:
                    return response.json(result)
            redisObject = RedisObject()
            values = uid_qs.values('uid')
            print(values)
            redisObject.set_data(key=token.token, val=json.dumps(list(values)), expire=3600)
            del datas
            del updates
            return response.json(0)
        else:
            return response.json(444)

    def do_update(self, datas, updates, savePoint, count=0):
        try:
            try:
                UserUIDModel.objects.bulk_create(datas)
                UIDModel.objects.bulk_update(updates, fields=['status', 'update_time'])
                datas.clear()
                updates.clear()
            except Exception as e:
                if savePoint:
                    transaction.savepoint_rollback(savePoint)
                djangoLogger = logging.getLogger('django')
                djangoLogger.exception(repr(e))
                return 174
        except Exception as e:
            return 174
        return 0

    # 把UID表中的数据移动到HistoryUID表中
    def do_remove(self, request_dict, response):
        token = TokenObject(request_dict.get('token', None))
        id = request_dict.get('id', None)
        start = request_dict.get('start', None)
        stop = request_dict.get('stop', None)

        if token.code != 0:
            return response.json(token.code)

        # 通过userID查找用户，判断是否是管理员
        user_qs = UserModel.objects.filter(id=token.userID)
        if user_qs.exists():
            user = user_qs[0]
            if user.permission != '0':
                return response.json(404)
        else:
            return response.json(9)

        if id:
            return self.do_remove_by_id(id, response)
        elif start and stop:
            return self.do_bulk_remove(int(start), int(stop), response)
        else:
            return response.json(444, 'id,start,stop')

    # 移除单条UID记录，id：记录id
    def do_remove_by_id(self, id, response):
        id = int(id)
        uid_qs = UIDModel.objects.filter(id=id)
        if not uid_qs.exists():
            return response.json(173)

        uid = uid_qs[0]
        if uid:
            data = {
                'uid': uid.uid,
                'uid_extra': uid.uid_extra,
                'status': uid.status,
                'add_time': uid.add_time,
                'update_time': uid.update_time,
                'area': uid.area
            }
            HistoryUIDModel.objects.create(**data)
            uid.delete()
            return response.json(0)
        else:
            return response.json(444, 'id')

    # 批量移除UID记录。start：开始的UID记录的id；stop：结束的UID记录的id
    def do_bulk_remove(self, start, stop, response):
        uid_qs = UIDModel.objects.filter(id__range=(start, stop))
        histories = []
        if uid_qs.exists():
            for item in uid_qs:
                histories.append(HistoryUIDModel(
                    uid=item.uid,
                    uid_extra=item.uid_extra,
                    status=item.status,
                    add_time=item.add_time,
                    update_time=item.update_time,
                    area=item.area
                ))
                if len(histories) % 5000 == 0:
                    HistoryUIDModel.objects.bulk_create(histories)
                    histories.clear()
            if len(histories) > 0:
                HistoryUIDModel.objects.bulk_create(histories)
                histories.clear()
            uid_qs.delete()
            return response.json(0)
        else:
            return response.json(173)

    def download_txt(self, token, response):

        redisObject = RedisObject()
        uid_qs = redisObject.get_data(key=token.token)

        if uid_qs is False:
            return response.json(308)

        uid_qs = json.loads(uid_qs)
        content = ''
        for item in uid_qs:
            # print(item)
            content += item['uid']
            content += '\r\n'

        redisObject.del_data(key=token.token)

        content = content[0:len(content) - 1]
        response = StreamingHttpResponse(content)
        response['Content-Type'] = 'application/octet-stream'
        filename = 'uid_need_to_set_up_push.txt'
        response['Content-Disposition'] = 'attachment;filename=' + filename

        return response

    def download_txt_two(self, token, response):

        uid_qs = UIDModel.objects.filter(status=1)

        if not uid_qs.exists():
            return response.json(308)

        uid_qs = uid_qs.values()
        content = ''
        for item in uid_qs:
            # print(item)
            content += item['uid']
            content += '\r\n'

        content = content[0:len(content) - 1]
        response = StreamingHttpResponse(content)
        response['Content-Type'] = 'application/octet-stream'
        filename = 'uid_need_to_set_up_push.txt'
        response['Content-Disposition'] = 'attachment;filename=' + filename

        return response

    def do_list(self, request_dict, response):
        page = request_dict.get('page', None)
        line = request_dict.get('limit', None)
        status = request_dict.get('status', None)
        area = request_dict.get('area', None)
        start_time = request_dict.get('starttime', None)
        stop_time = request_dict.get('endtime', None)
        uid = request_dict.get('uid', None)

        if page and line:

            uid_qs = UIDModel.objects.filter()
            res = {
                'count': 0,
                'data': []
            }

            if uid_qs.exists():
                page = int(page)
                line = int(line)

                start = (page - 1) * line
                end = start + line

                if uid:
                    uid_qs = uid_qs.filter(uid=uid)

                if status:
                    uid_qs = uid_qs.filter(status=status)

                if area:
                    uid_qs = uid_qs.filter(area=area)

                if start_time:
                    uid_qs = uid_qs.filter(update_time__gte=start_time)

                if stop_time:
                    if stop_time > start:
                        uid_qs = uid_qs.filter(update_time__lte=stop_time)

                res['count'] = uid_qs.count()
                uid_qs = uid_qs.values()[start:end]

                res['data'] = list(uid_qs)

            print(res)
            return response.json(0, res)
        else:
            return response.json(444)

    def do_delete(self, userID, request_dict, response):
        uid = request_dict.get('uid', None)
        user_qs = UserModel.objects.filter(id=userID)

        if user_qs.exists():
            user = user_qs[0]
            if int(user.permission) != 0:
                return response.json(309)

            UIDModel.objects.filter(uid=uid).delete()
            return response.json(0)
        else:
            return response.json(309)

    def do_batch_delete(self, userID, request_dict, response):
        perm = ModelService.check_perm(userID, 0)
        if not perm:
            return response.json(309)

        uids = request_dict.get('uidlist', None)

        if uids:
            uids = json.loads(uids)
            UIDModel.objects.filter(uid__in=uids).delete()
            return response.json(0)
        else:
            return response.json(444)

    def do_admin_update(self, userID, request_dict, response):
        perm = ModelService.check_perm(userID, 0)
        if not perm:
            return response.json(309)

        uid = request_dict.get('uid', None)
        content = request_dict.get('content', None)
        print(content)

        if uid and content:
            content = json.loads(content)
            print(content)
            content['update_time'] = int(time.time())
            uid_qs = UIDModel.objects.filter(uid=uid)
            if uid_qs.exists():
                uid_qs.update(**content)
                return response.json(0)
            else:
                return response.json(173)
        else:
            return response.json(444)

    def do_history(self, userID, request_dict, response):
        perm = ModelService.check_perm(userID, 0)
        if not perm:
            return response.json(309)

        uid_qs = UIDModel.objects.filter(status=2)

        if uid_qs.exists():

            uids = []
            for uid in uid_qs:
                uids.append(uid)

                if (len(uids) % 5000) == 0:
                    HistoryUIDModel.objects.bulk_create(uids)
                    uids.clear()

            if len(uids) > 0:
                HistoryUIDModel.objects.bulk_create(uids)
                uids.clear()

        uid_qs.delete()

        return response.json(0)

    def do_admin_statistics(self, userID, request_dict, response):
        perm = ModelService.check_perm(userID, 0)
        if not perm:
            return response.json(309)

        uid_not_use = UIDModel.objects.filter(status=0).count()

        uid_allocated = UIDModel.objects.filter(status=1).count()

        uid_has_use = UIDModel.objects.filter(status=2).count()

        total = uid_not_use + uid_allocated + uid_has_use

        res = {
            'uid_not_use': uid_not_use,
            'uid_allocated': uid_allocated,
            'uid_has_use': uid_has_use,
            'total': total
        }

        return response.json(0, res)

