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

from django.db import transaction
from django.views import View

from Controller.DeviceConfirmRegion import Device_Region
from Model.models import SerialNumberModel, CompanySerialModel, UIDCompanySerialModel, CompanyModel, RegionModel, \
    CountryModel, UIDModel, Device_Info, iotdeviceInfoModel
from Object.RedisObject import RedisObject
from Object.uidManageResponseObject import uidManageResponseObject
from Object.TokenObject import TokenObject
from Service.AlgorithmService import AlgorithmBaseOn35
from Service.CommonService import CommonService
from Service.ModelService import ModelService


class SerialNumberView(View):

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

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

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

        if operation == 'getUID':
            return self.do_get_uid(request_dict, response)
        elif operation == 'getSerial':
            return self.do_get_serial_number(request_dict, response)
        elif operation == 'attachUID':
            return self.do_attach_uid(request_dict, response, request)
        elif operation == 'detachUID':
            return self.do_detach_uid(request_dict, response)
        elif operation == 'create':
            return self.do_create(request_dict, response)
        else:
            if token.code != 0:
                return response.json(token.code)

            # if operation == 'create':
            #     return self.do_create(request_dict, response)
            elif operation == 'list':
                return self.do_list(token.userID, request_dict, response)
            elif operation == 'update':
                return self.do_update(token.userID, request_dict, response)
            else:
                return response.json(404)

    def do_create(self, request_dict, response):
        quantity = int(request_dict.get('quantity', 0))
        p2p = int(request_dict.get('p2p', 0))

        if not quantity:
            return response.json(444)

        try:
            try:
                sum = SerialNumberModel.objects.last().id
            except:
                sum = 0
            serial_number_bulk = []
            now_time = int(time.time())
            algorithm = AlgorithmBaseOn35()
            for i in range(quantity):
                serial_number = algorithm.getLetter(sum)
                sum += 1    # sum每次递增1
                # 前面补0至六位
                serial_number = (6-len(serial_number))*'0' + serial_number
                serial_number_bulk.append(SerialNumberModel(serial_number=serial_number, add_time=now_time, p2p=p2p))
            # 开启事务写入
            with transaction.atomic():
                SerialNumberModel.objects.bulk_create(serial_number_bulk)
            return response.json(0)
        except Exception as e:
            print(e)
            return response.json(500, repr(e))

    # 提供给pc端获取序列号
    def do_get_serial_number(self, request_dict, response):
        quantity = request_dict.get('quantity', None)
        company_id = request_dict.get('company_id', None)
        token = request_dict.get('token', None)
        time_stamp = request_dict.get('time_stamp', None)
        p2p_type = request_dict.get('p2p_type', None)

        if token and time_stamp and quantity and company_id:

            token = int(CommonService.decode_data(token))
            time_stamp = int(time_stamp)

            now_time = int(time.time())
            distance = now_time - time_stamp

            if token != time_stamp or distance > 60000 or distance < -60000: #为了全球化时间控制在一天内
                return response.json(404)

            redisObject = RedisObject()
            key = 'serial_lock'
            value = redisObject.lpop(key)
            count = 0
            while value is False and count < 5:
                time.sleep(1)
                value = redisObject.lpop(key)
                count += 1

            if count == 5 and value is False:    #暂时注释
                return response.json(5)

            quantity = int(quantity)

            company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_id, status=0, p2p=p2p_type)
            if not company_serial_qs.exists():
                redisObject.rpush(key, value)
                return response.json(373)

            # 存在对应的企业
            company_serial_qs = company_serial_qs[0:quantity]

            #company_serial_qs = company_serial_qs.values('id', 'serial_number__serial_number', 'company__mark')
            data = []
            ids = []
            for serial in company_serial_qs:
                ids.append(serial.id)
                data.append(serial.serial_number + serial.company.mark)
            CompanySerialModel.objects.filter(id__in=ids).update(status=1)
            redisObject.rpush(key, value)
            return response.json(0, data)
        else:
            return response.json(444)

    def do_list(self, userID, request_dict, response):
        # perm = ModelService.check_perm_uid_manage(userID, 0)
        # if not perm:
        #     return response.json(309)

        page = request_dict.get('page', None)
        line = request_dict.get('limit', None)
        serial_number = request_dict.get('serial_number', None)
        status = request_dict.get('status', None)

        if page and line:
            page = int(page)
            line = int(line)

            serial_qs = SerialNumberModel.objects.filter().order_by('-id')

            if serial_number:
                serial_qs = serial_qs.filter(serial_number__contains=serial_number)

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

            count = serial_qs.count()

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

            serial_qs = serial_qs[start: end].values()
            res = {
                'count': count,
                'data': list(serial_qs)
            }

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

    @transaction.atomic
    def do_attach_uid(self, request_dict, response, request):
        serial_number = request_dict.get('serial_number', None)
        country_id = request_dict.get('country_id', None)
        company_id = request_dict.get('company_id', None)
        token = request_dict.get('token', None)
        time_stamp = request_dict.get('time_stamp', None)

        if serial_number and len(serial_number) == 9  and company_id:

            token = int(CommonService.decode_data(token))
            time_stamp = int(time_stamp)

            now_time = int(time.time())
            distance = now_time - time_stamp

            if token != time_stamp or distance > 60000 or distance < -60000: #为了全球化时间控制在一天内
                return response.json(404)

            mark = serial_number[6:9]
            serial = serial_number[0:6]

            savePoint = transaction.savepoint()
            try:
                try:
                    if not country_id :
                        ip = CommonService.get_ip_address(request)
                        country_id = Device_Region().get_device_region(ip)

                    # 判断序列号是否已和企业关联
                    company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_id,
                                                                          serial_number=serial)
                    if not company_serial_qs.exists():
                        return response.json(173)

                    # 当序列号已关联UID
                    company_serial = company_serial_qs[0]

                    if company_serial.status == 0:
                        # 该序列号未绑定企业
                        return response.json(173)
                    elif company_serial.status == 1:
                        # 确定所在区域
                        country_qs = CountryModel.objects.filter(number=country_id)
                        if not country_qs.exists():
                            return response.json(374)

                        region = country_qs.values('region_id')[0]

                        count = 0
                        while count < 3:
                            p2p = SerialNumberModel.objects.filter(serial_number=serial).values('p2p')
                            print('此序列号的p2p类型：', p2p[0]['p2p'])
                            uid_qs = UIDModel.objects.filter(vpg__company_id=company_serial.company.id, vpg__region_id=region['region_id'],
                                                             status=0, p2p_type=p2p[0]['p2p']).order_by('id')[0:10]
                            # uid_qs：未进行绑定的uid列表
                            if uid_qs.exists():
                                uid = uid_qs[0]
                                # uid.status = 2
                                # uid.update_time = int(time.time())
                                result = UIDModel.objects.filter(id=uid.id, status=0).update(**{
                                    'status': 2, 'update_time': int(time.time())
                                })

                                if int(result) <= 0:
                                    count += 1
                                    continue

                                now_time = int(time.time())
                                uid_serial = UIDCompanySerialModel(uid_id=uid.id, company_serial_id=company_serial.id,
                                                                   add_time=now_time, update_time=now_time)
                                uid_serial.save()

                                company_serial.status = 2
                                company_serial.save()

                                dev = Device_Info.objects.filter(UID=uid.uid)
                                if dev.exists():
                                    dev.update(serial_number=serial_number)

                                res = {
                                    'full_uid_code': CommonService.encode_data(uid.full_uid_code),
                                    'uid': CommonService.encode_data(uid.uid),
                                    'mac': CommonService.encode_data(uid.mac),
                                    'extra': uid.uid_extra
                                }
                                return response.json(0, res)
                            else:
                                return response.json(375)

                        return response.json(5)
                    else:
                        uid_qs = UIDCompanySerialModel.objects.filter(company_serial_id=company_serial.id)
                        if uid_qs.exists():
                            uid = uid_qs.values('uid__uid', 'uid__mac', 'uid__uid_extra', 'uid__full_uid_code')[0]
                            res = {
                                'full_uid_code': CommonService.encode_data(uid['uid__full_uid_code']),
                                'uid': CommonService.encode_data(uid['uid__uid']),
                                'mac': CommonService.encode_data(uid['uid__mac']),
                                'extra': uid['uid__uid_extra']
                            }
                            return response.json(0, res)
                        else:
                            return response.json(173)
                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(176, str(e))
            except Exception as e:
                # print('--------------------------error 5001')
                # print(repr(e))
                djangoLogger = logging.getLogger('django')
                djangoLogger.exception(repr(e))
                return response.json(176, str(e))

        else:
            return response.json(444)

    def do_get_uid(self, request_dict, response):
        serial_number = request_dict.get('serial_number', None)
        token = request_dict.get('token', None)
        time_stamp = request_dict.get('time_stamp', None)

        if token and time_stamp and serial_number and len(serial_number) == 9:

            token = int(CommonService.decode_data(token))
            time_stamp = int(time_stamp)

            now_time = int(time.time())
            distance = now_time - time_stamp

            if token != time_stamp or distance > 60000 or distance < -60000:  #为了全球化时间控制在一天内
                return response.json(404)

            mark = serial_number[6:9]
            serial = serial_number[0:6]
            uid_company_serial_qs = UIDCompanySerialModel.objects.filter(company_serial__company__mark=mark, company_serial__serial_number__serial_number=serial)

            if uid_company_serial_qs.exists():
                uid = uid_company_serial_qs.values('uid__uid', 'uid__mac', 'uid__uid_extra')[0]

                res = {
                    'uid': CommonService.encode_data(uid['uid__uid']),
                    'mac': CommonService.encode_data(uid['uid__mac']),
                    'extra': uid['uid__uid_extra']
                }

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

    def do_detach_uid(self, request_dict, response):
        serial_number = request_dict.get('serial_number', None)
        token = request_dict.get('token', None)
        time_stamp = request_dict.get('time_stamp', None)

        if token and time_stamp and serial_number:
            token = int(CommonService.decode_data(token))
            time_stamp = int(time_stamp)

            now_time = int(time.time())
            distance = now_time - time_stamp

            if token != time_stamp or distance > 60000 or distance < -60000:  # 为了全球化时间控制在一天内
                return response.json(404)

            serial = serial_number[0:6]

            uid_serial_qs = UIDCompanySerialModel.objects.filter(company_serial__serial_number=serial)
            if uid_serial_qs.exists():
                uid_serial = uid_serial_qs[0]

                #iot = iotdeviceInfoModel.objects.filter(serial_number__serial_number=serial)
                iot = iotdeviceInfoModel.objects.filter(thing_name="Ansjer_Device_" + serial_number)
                if iot.exists():
                    iot.delete()

                company_serial_qs = CompanySerialModel.objects.filter(id=uid_serial.company_serial.id)
                if company_serial_qs.exists():
                    company_serial = company_serial_qs[0]
                    company_serial.status = 1
                    company_serial.save()

                uid_qs = UIDModel.objects.filter(uid=uid_serial.uid.uid)
                if uid_qs.exists():
                    uid = uid_qs[0]
                    uid.status = 0
                    uid.save()
                uid_serial.delete()

                dev = Device_Info.objects.filter(serial_number=serial_number)
                if dev.exists():
                    dev.update(serial_number='')
                return response.json(0)
            else:
                return response.json(173)
        else:
            return response.json(444)

    def do_update(self, userID, request_dict, response):
        # perm = ModelService.check_perm_uid_manage(userID, 0)
        # if not perm:
        #     return response.json(309)

        id = request_dict.get('id', None)
        status = request_dict.get('status', None)
        p2p = request_dict.get('p2p', None)

        if id and status:
            serial_number_qs = SerialNumberModel.objects.filter(id=id)
            if serial_number_qs.exists():
                serial_number_qs.update(**{'status': status, 'p2p': p2p})
                return response.json(0)
            else:
                return response.json(173)
        else:
            return response.json(444)