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

import xlwt

from django.http import StreamingHttpResponse, HttpResponse, QueryDict
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.db import transaction

from Ansjer.config import BASE_DIR
from Model.models import UIDModel, UserUIDModel, UserModel, LogModel, MacModel, OrderTaskModel, OrderUIDModel
from Object.RedisObject import RedisObject
from Object.TokenObject import TokenObject
from Object.uidManageResponseObject import uidManageResponseObject
from Service.CommonService import CommonService


class UploadUIDFileView(View):

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

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

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

    def validate(self, fileName, request_dict, request):
        token = request_dict.get('token', None)
        area = request_dict.get('area', None)
        isReset = request_dict.get('isReset', 0)
        content = request_dict.get('fileName', None)
        vpg_id = request_dict.get('vpg_id', None)

        print('content')
        print(content)

        content = base64.b64decode(content).decode().strip()
        content = content[3:(len(content) - 3)]
        uids = content.split('\n')
        # print(uids)
        # print(len(uids))

        response = uidManageResponseObject()

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

        # if not fileName and not area:
        #     return response.json(444, 'fileName,area')

        data = {}
        duplicate = []
        for line in uids:

            if len(line) < 20:
                continue

            if data.__contains__(line):
                duplicate.append(line)
            else:
                data[line] = ''

        if isReset == 0:
            return self.do_insert(data, duplicate, vpg_id, area, response, request, tko)
        else:
            return self.do_reset(data, response, area, request, tko)

    @transaction.atomic
    def do_insert(self, data, duplicate, vpg_id, area, response, request, token):
        bulk = []
        count = 0
        add_time = int(time.time())
        update_time = int(time.time())
        keys = data.keys()

        # 获取最新的mac
        mac = MacModel.objects.filter().values('id', 'value', 'is_active')[0]
        if not mac['is_active']:
            return response.json(175)
        # redisObject = RedisObject(db=3)
        key = ''
        tmpMac = mac['value']
        savePoint = None
        for item in keys:
            key = item.strip()
            # value = redisObject.get_data(key)
            # if value is False:
            #     # redisObject.set_data(key, '1', 600)
            # else:
            #     duplicate.append(key)
            #     continue
            bulk.append(UIDModel(
                uid=item.strip(),
                uid_extra='',
                status=0,
                add_time=add_time,
                update_time=update_time,
                area=area,
                mac=mac['value'],
                vpg_id=vpg_id
            ))
            try:
                try:
                    if (count % 5000) == 0:
                        savePoint = transaction.savepoint()
                        UIDModel.objects.bulk_create(bulk)
                        bulk.clear()
                        data = {
                            'value': mac['value'],
                            'is_active': tmpMac is not None
                        }
                        MacModel.objects.filter().update(**data)
                except Exception as e:
                    # print('--------------------------error 5000')
                    # print(repr(e))
                    if savePoint:
                        transaction.rollback(savePoint)
                    djangoLogger = logging.getLogger('django')
                    djangoLogger.exception(repr(e))
                    return response.json(174, str(e))
                else:
                    savePoint = None
            except Exception as e:
                # print('--------------------------error 5001')
                # print(repr(e))
                djangoLogger = logging.getLogger('django')
                djangoLogger.exception(repr(e))
                return response.json(174, str(e))
            count += 1
            tmpMac = CommonService.updateMac(mac['value'])
            if tmpMac is None:
                # 能分配的mac已用完
                break
            else:
                mac['value'] = tmpMac

        # 当bulk不足5000时，还有数据要插入
        try:
            try:
                savePoint = transaction.savepoint()  # 事务保存点
                if len(bulk) > 0:
                    UIDModel.objects.bulk_create(bulk)
                    bulk.clear()
            except Exception as e:
                # print('--------------------------error')
                # print(repr(e))
                if savePoint:
                    transaction.rollback(savePoint)
                djangoLogger = logging.getLogger('django')
                djangoLogger.exception(repr(e))
                return response.json(174)
            else:
                del data
                del bulk
                data = {
                    'value': mac['value'],
                    'is_active': tmpMac is not None
                }
                MacModel.objects.filter().update(**data)
        except Exception as e:
            # print('--------------------------error 1111')
            # print(repr(e))
            djangoLogger = logging.getLogger('django')
            djangoLogger.exception(repr(e))
            return response.json(174)

        # print('重复：')
        # print(duplicate)

        try:
            operation = self.formatOperation(operation='上传', quantity=int(count), area=int(area))
            print(operation)
            self.add_log(request, operation, token)
        except Exception as e:
            djangoLogger = logging.getLogger('django')
            djangoLogger.exception(repr(e))

        if tmpMac is None:
            return response.json(175, {'last_uid': key})
        return response.json(0, {'count': count, 'duplicate_count': len(duplicate), 'data': duplicate})

    def do_reset(self, data, response, area, request, token):
        keys = data.keys()
        uids = []
        count = 0
        for key in keys:
            uids.append(key.strip())
            if len(uids) % 5000 == 0:
                count += self.do_update_uid_status(uids, area)
                uids.clear()

        if len(uids) > 0:
            count += self.do_update_uid_status(uids, area)
            uids.clear()

        operation = self.formatOperation('重置', int(count), int(area))
        self.add_log(request, operation, token)
        return response.json(0)

    def do_update_uid_status(self, uids, area):
        uid_qs = UIDModel.objects.filter(uid__in=uids, area=area, status=2)
        if uid_qs.exists():
            uid_ids = []
            for uid in uid_qs:
                if uid.status == 2:
                    uid.status = 1
                    uid_ids.append(uid.id)
            UIDModel.objects.bulk_update(uid_qs, fields=['status'])

            try:
                OrderUIDModel.objects.filter(uid__id__in=tuple(uid_ids)).delete()
            except Exception as e:
                print(e)

            return uid_qs.count()
        return 0

    def add_log(self, request, operation, token):
        ip = CommonService.get_ip_address(request)
        now_time = time.time()
        content = json.loads(json.dumps(request.POST))
        user_qs = UserModel.objects.filter(id=token.userID)

        if content.__contains__('fileName'):
            del content['fileName']
        log = {
            'status': 200,
            'content': json.dumps(content),
            'ip': ip,
            'time': now_time,
            'url': 'upload',
            'operation': operation,
            'user': user_qs[0]
        }

        try:
            LogModel.objects.create(**log)
        except Exception as e:
            print('出错')
            print(repr(e))

    def formatOperation(self, operation, quantity, area):
        str = '{operation}{quantity}个{area}UID'
        if area == 0:
            return str.format(operation=operation, quantity=quantity, area='国内')
        else:
            return str.format(operation=operation, quantity=quantity, area='国外')


class DownloadUIDFileView(View):

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

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

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

    def validate(self, request_dict):
        token = request_dict.get('token', None)
        area = request_dict.get('area', None)
        quantity = int(request_dict.get('quantity', None))
        fileType = request_dict.get('fileType', None)
        order_number = request_dict.get('order_number', None)
        board = request_dict.get('board', None)
        plan = request_dict.get('plan', None)
        checksum = request_dict.get('checksum', None)
        ic_model = request_dict.get('ic_model', None)
        order_quantity = request_dict.get('order_quantity', None)
        response = uidManageResponseObject()

        # print(area)
        # print(quantity)
        token = TokenObject(token)
        if token.code != 0:
            return response.json(token.code)

        if not area or not order_number or not board or not plan or not checksum or not ic_model or not order_quantity or not fileType:
            return response.json(444)

        area = int(area)

        if area >= 0 and quantity > 0:

            # 保存订单信息
            now_time = int(time.time())
            order = {
                'order_number': order_number,
                'board': board,
                'plan': plan,
                'checksum': checksum,
                'ic_model': ic_model,
                'quantity': order_quantity,
                'add_time': now_time
            }

            tmp = OrderTaskModel.objects.create(**order)
            print(tmp)

            order = OrderTaskModel.objects.filter(order_number=order_number).order_by('-add_time')[0]

            uid_qs = UserUIDModel.objects.filter(user__id=token.userID, uid__status=1, uid__area=area)

            uid_values = uid_qs.values('uid__id', 'uid__uid', 'uid__mac', 'uid__uid_extra', 'uid__add_time', 'uid__update_time', 'uid__area')

            count = uid_values.count()
            if count < quantity:
                return response.json(444, '设备UID不足')

            if uid_values.exists():

                uid_values = uid_values[0:quantity]
                uid_qs = uid_qs[0: quantity]
                if fileType == 'txt':
                    # return self.download_txt(uid_values, uid_qs, order)
                    # return self.download_excel(uid_values, order)
                    return self.download_zip(uid_values, order)
                elif fileType == 'excel':
                    return self.download_excel(uid_values, order)
                else:
                    return response.json(444, 'fileType')
            else:
                return response.json(444, '111')
        else:
            return response.json(444, '222')

    def download_txt(self, uid_values, uid_qs, order):
        updates = []
        updates_uid = []
        content = ''
        now_time = int(time.time())
        for i in range(len(uid_values)):
            # print(item)
            item = uid_values[i]
            mac = str(item['uid__mac'])
            index = mac.rfind(':')
            tmp = mac[0:index] + '\t' + mac[index:]
            content += tmp + '\t'
            content += item['uid__uid'].strip()
            content += '\r\n'
            uidModel = UIDModel(
                id=item['uid__id'],
                uid=item['uid__uid'],
                mac=item['uid__mac'],
                uid_extra=item['uid__uid_extra'],
                status=2,
                add_time=item['uid__add_time'],
                update_time=now_time,
                area=item['uid__area']
            )
            updates.append(uidModel)

            order_uid = OrderUIDModel(uid=uidModel, order=order, add_time=now_time, update_time=now_time)
            updates_uid.append(order_uid)

            if len(updates) % 5000 == 0:
                UIDModel.objects.bulk_update(updates, fields=["status"])
                OrderUIDModel.objects.bulk_create(updates_uid)
                updates.clear()
                updates_uid.clear()
            # print(item['uid__uid'])

        if len(updates) > 0:
            UIDModel.objects.bulk_update(updates, fields=["status"])
            OrderUIDModel.objects.bulk_create(updates_uid)
            updates.clear()
            updates_uid.clear()

        del updates
        del updates_uid
        content = content[0:len(content) - 1]
        response = StreamingHttpResponse(content)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename=UID'+time.strftime('-%Y-%m-%d-%H-%M-%S', time.localtime()) + '.txt'
        return response

    def download_excel(self, uid_qs, order):
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = 'attachment; filename=UID' + time.strftime('-%Y-%m-%d-%H-%M-%S',
                                                                                     time.localtime()) + '.xls'
        workbook = xlwt.Workbook(encoding='utf-8')
        sheet1 = workbook.add_sheet('UID')
        # row1 = [u'设备UID']
        # for i in range(0, len(row1)):
        #     sheet1.write(0, i, row1[i])

        num = 1
        updates = []
        updates_uid = []
        now_time = int(time.time())
        for item in uid_qs:
            uid = item['uid__uid']
            mac = item['uid__mac']
            index = mac.rfind(':')
            sheet1.write(num, 0, mac[0:index])
            sheet1.write(num, 1, mac[index:])
            sheet1.write(num, 2, uid)
            num += 1
            uidModel = UIDModel(
                id=item['uid__id'],
                uid=item['uid__uid'],
                mac=item['uid__mac'],
                uid_extra=item['uid__uid_extra'],
                status=2,
                add_time=item['uid__add_time'],
                update_time=now_time,
                area=item['uid__area']
            )
            updates.append(uidModel)

            order_uid = OrderUIDModel(uid=uidModel, order=order, add_time=now_time, update_time=now_time)
            updates_uid.append(order_uid)

            if len(updates) % 5000 == 0:
                UIDModel.objects.bulk_update(updates, fields=["status"])
                OrderUIDModel.objects.bulk_create(updates_uid)
                updates.clear()
                updates_uid.clear()
            # print(item['uid__uid'])

        if len(updates) > 0:
            UIDModel.objects.bulk_update(updates, fields=["status"])
            OrderUIDModel.objects.bulk_create(updates_uid)
            updates.clear()
            updates_uid.clear()

        UIDModel.objects.bulk_update(updates, fields=["status"])
        workbook.save(response)
        return response

    def download_zip(self, uid_qs, order):
        dir_name = 'static/' + time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime())
        path = '/'.join((BASE_DIR, dir_name)).replace('\\', '/') + '/'
        if not os.path.exists(path):
            os.mkdir(path)

        filename = time.strftime('_%Y_%m_%d_%H_%M_%S', time.localtime())
        txt_filename = 'UID' + filename + '.txt'
        excel_filename = 'UID' + filename + '.xls'

        txt_file = open(path + txt_filename, 'w+')
        workbook = xlwt.Workbook(encoding='utf-8')
        sheet1 = workbook.add_sheet('UID')
        num = 1

        updates = []
        updates_uid = []
        content = ''
        now_time = int(time.time())
        for i in range(len(uid_qs)):
            # print(item)
            item = uid_qs[i]
            uid = item['uid__uid']
            mac = item['uid__mac']
            index = mac.rfind(':')
            tmp = mac[0:index] + '\t' + mac[index:]
            content += tmp + '\t'
            content += item['uid__uid'].strip()
            content += '\r\n'

            sheet1.write(num, 0, mac[0:index])
            sheet1.write(num, 1, mac[index:])
            sheet1.write(num, 2, uid)
            num += 1

            uidModel = UIDModel(
                id=item['uid__id'],
                uid=item['uid__uid'],
                mac=item['uid__mac'],
                uid_extra=item['uid__uid_extra'],
                status=2,
                add_time=item['uid__add_time'],
                update_time=now_time,
                area=item['uid__area']
            )
            updates.append(uidModel)

            order_uid = OrderUIDModel(uid=uidModel, order=order, add_time=now_time, update_time=now_time)
            updates_uid.append(order_uid)

            if len(updates) % 5000 == 0:
                UIDModel.objects.bulk_update(updates, fields=["status"])
                OrderUIDModel.objects.bulk_create(updates_uid)
                updates.clear()
                updates_uid.clear()
            # print(item['uid__uid'])

        if len(updates) > 0:
            UIDModel.objects.bulk_update(updates, fields=["status"])
            OrderUIDModel.objects.bulk_create(updates_uid)
            updates.clear()
            updates_uid.clear()

        del updates
        del updates_uid
        content = content[0:len(content) - 1]
        txt_file.write(content)
        txt_file.close()

        workbook.save(path + excel_filename)

        zip_name = path[0:path.rfind('/')] + '.zip'
        return self.get_zip(path, os.listdir(path), zip_name)

    def get_zip(self, path, files, zip_name):
        zp = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
        for file in files:
            zp.write(filename=(path + file), arcname=str(file))
        zp.close()

        response = StreamingHttpResponse(open(zip_name, 'rb'))
        response['content_type'] = "application/octet-stream"
        response['Content-Disposition'] = 'attachment; filename=UID' + time.strftime('_%Y_%m_%d_%H_%M_%S',
                                                                                     time.localtime()) + '.zip'
        return response

