from base_resource import BaseResource, SendBaseResource
from mysql_model import PersonModel, DeviceModel
from werkzeug.datastructures import FileStorage
from datetime import datetime
import os, werkzeug, base64, pandas as pd

os.makedirs(os.path.join('static', 'excel'), 0o777, True)

# ========== 新增使用者資源 ==========
class PersonInsert(BaseResource):
    def __init__(self):
        super().__init__("InsertPerson")
        self.parser.add_argument('id', required=True, help="上限 10 字")
        self.parser.add_argument('name', required=True, help="上限 10 字")
        self.parser.add_argument('sex', required=True, help="1:男, 2: 女, 3:未知")
        self.parser.add_argument('type', required=True, help="1:黑名單, 2: 白名單, 3:VIP名單")
        self.parser.add_argument('token')
        self.parser.add_argument('photo', required=True, type=FileStorage, location='files')
        self.parser.add_argument('start', help="yyyy-MM-dd HH:mm:ss")
        self.parser.add_argument('end', help="yyyy-MM-dd HH:mm:ss")
    def post(self):
        args = self.parser.parse_args()
        model = PersonModel.FromDB(args['id'], self.log.SetMessage)
        if not model.isExist:
            if isinstance(args['photo'], FileStorage) and bool(args['photo']):
                filename = "{0}.jpg".format(os.path.join("static", "person", args['id']))
                args['photo'].save(filename)
                model.SetName(args['name'])
                model.SetSex(args['sex'])
                model.SetType(args['type'])
                model.SetToken(args['token'])
                model.SetPhoto(filename)
                if model.SetStart(args['start']):
                    if model.SetEnd(args['end']):
                        devices = DeviceModel.AllFromDB(self.log.SetMessage)
                        failed = []
                        for device in devices:
                            if not device.InsertToDevice(model):
                                if device.GetType() == 5:
                                    self.result = 10 if device.ResultCode == -3 else self.result
                                    self.result = 11 if device.ResultCode == -15 else self.result
                                    device.ResultCode = "ID 無法使用" if device.ResultCode == -3 else device.ResultCode
                                    device.ResultCode = "人臉偵測失敗" if device.ResultCode == -15 else device.ResultCode
                                    failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                                if device.GetType() == 4:
                                    self.result = 1000 if device.ResultCode == -1000 else self.result
                                    self.result = 1003 if device.ResultCode == -1003 else self.result
                                    self.result = 1004 if device.ResultCode == -1004 else self.result
                                    self.result = 2001 if device.ResultCode == -2001 else self.result
                                    self.result = 2002 if device.ResultCode == -2002 else self.result
                                    self.result = 2003 if device.ResultCode == -2003 else self.result
                                    self.result = 2004 if device.ResultCode == -2004 else self.result
                                    self.result = 2005 if device.ResultCode == -2005 else self.result
                                    self.result = 2006 if device.ResultCode == -2006 else self.result
                                    device.ResultCode = "Undefined Errcode" if device.ResultCode == -1000 else device.ResultCode
                                    device.ResultCode = "Token無效" if device.ResultCode == -1003 else device.ResultCode
                                    device.ResultCode = "設備在伺服器中沒有註冊" if device.ResultCode == -1004 else device.ResultCode
                                    device.ResultCode = "JSON字串轉換JavaScript數值或物件錯誤" if device.ResultCode == -2001 else device.ResultCode
                                    device.ResultCode = "超過資料庫的最大數量" if device.ResultCode == -2002 else device.ResultCode
                                    device.ResultCode = "無法取得Java Feature" if device.ResultCode == -2003 else device.ResultCode
                                    device.ResultCode = "無效的JPG圖檔格式" if device.ResultCode == -2004 else device.ResultCode
                                    device.ResultCode = "SDcard 無法讀取" if device.ResultCode == -2005 else device.ResultCode
                                    device.ResultCode = "Model SDK 無法正常初始化" if device.ResultCode == -2006 else device.ResultCode
                                    failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                                if device.GetType() == 2:
                                    failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                        if len(failed) == 0 or True:
                            if model.InsertToDB(self.log.SetMessage):
                                self.message = "{0} inserted".format(args['id'])
                                if len(failed) != 0:
                                    self.message = "{0} inserted, device {1} upload failed".format(args['id'],', '.join(failed))
                            else:
                                self.result = 10
                                self.message = "{0} insert failed".format(args['id'])
                        else:
                            # 109.12.17 若有設備人員新增失敗，則刪除所有設備上的人員
                            for device in devices:
                                device.DeleteFromDevice(model)
                            self.message = "{0} insert failed, because device {1} upload failed".format(args['id'], ', '.join(failed))
                    else:
                        self.message = "the format of end time {0} isn't match".format(args['end'])
                else:
                    self.message = "the format of start time {0} isn't match".format(args['start'])
            else:
                self.message = "photo type isn't match, has be file"
        else:
            self.result = 10
            self.message = "{0} is exist in database".format(args['id'])
        return self.GetResponse()
# ========== 新增使用者資源，圖檔從伺服器取得 ==========
class PersonInsertNoImage(BaseResource):
    def __init__(self):
        super().__init__("InsertPersonNoImage")
        self.parser.add_argument('id', required=True, help="上限 10 字")
        self.parser.add_argument('name', required=True, help="上限 10 字")
        self.parser.add_argument('sex', required=True, help="1:男, 2: 女, 3:未知")
        self.parser.add_argument('type', required=True, help="1:黑名單, 2: 白名單, 3:VIP名單")
        self.parser.add_argument('token')
        self.parser.add_argument('photo', required=True, help="時間戳記")
        self.parser.add_argument('start', help="yyyy-MM-dd HH:mm:ss")
        self.parser.add_argument('end', help="yyyy-MM-dd HH:mm:ss")
    def post(self):
        args = self.parser.parse_args()
        model = PersonModel.FromDB(args['id'], self.log.SetMessage)
        if not model.isExist or (model.isExist and model.GetPhoto()==None):
            if isinstance(args['photo'], str):
                filename1 = "{0}.jpg".format(os.path.join("static", "face", args['photo']))
                filename2 = "{0}.jpg".format(os.path.join("static", "person", args['id']))
                model.SetName(args['name'])
                model.SetSex(args['sex'])
                model.SetType(args['type'])
                model.SetToken(args['token'])
                model.SetPhoto(filename1)
                model.SetCreated()
                with open(filename2, "wb") as f:
                    photo = model.GetPhoto()
                    photo = base64.b64decode(photo)
                    f.write(photo)
                if os.path.isfile(filename1):
                    if model.SetStart(args['start']):
                        if model.SetEnd(args['end']):
                            devices = DeviceModel.AllFromDB(self.log.SetMessage)
                            failed = []
                            for device in devices:
                                if not device.InsertToDevice(model):
                                    if device.GetType() == 5:
                                        self.result = 10 if device.ResultCode == -3 else self.result
                                        self.result = 11 if device.ResultCode == -15 else self.result
                                        device.ResultCode = "ID 無法使用" if device.ResultCode == -3 else device.ResultCode
                                        device.ResultCode = "人臉偵測失敗" if device.ResultCode == -15 else device.ResultCode
                                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                                    if device.GetType() == 4:
                                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                                    if device.GetType() == 2:
                                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                                    print(failed[-1])
                            if len(failed) == 0:
                                if(model.isExist):
                                    ret=model.UpdateToDB(self.log.SetMessage)
                                else:
                                    ret=model.InsertToDB(self.log.SetMessage)
                                if ret:
                                    self.message = "{0} inserted".format(args['id'])
                                else:
                                    self.result = 10
                                    self.message = "{0} insert failed".format(args['id'])
                            else:
                                # 109.12.17 若有設備人員新增失敗，則刪除所有設備上的人員
                                for device in devices:
                                    device.DeleteFromDevice(model)
                                self.message = "{0} insert failed, because device {1} upload failed".format(args['id'], ', '.join(failed))
                        else:
                            self.message = "the format of end time {0} isn't match".format(args['end'])
                    else:
                        self.message = "the format of start time {0} isn't match".format(args['start'])
                else:
                    self.message = "file {0} is not exist".format(filename1)
            else:
                self.message = "photo type isn't match, has be timestramp"
        else:
            self.result = 10
            self.message = "{0} is exist in database".format(args['id'])
        return self.GetResponse()
class PersonInsertWithExcel(BaseResource):
    def __init__(self):
        super().__init__("PersonInsertWithExcel")
        self.parser.add_argument('excel', required=True, type=FileStorage, location='files')
    def post(self):
        args = self.parser.parse_args()
        now = datetime.now()
        now = datetime.timestamp(now)
        filename = "{0}.xlsx".format(os.path.join("static", "excel", str(now)))
        args['excel'].save(filename)
        excel = pd.read_excel(filename,header=None)
        insert = []
        not_insert = []
        if (excel.iloc[0,0]=="人員編號(英數混合最多10碼)" and excel.iloc[0,1]=="人員姓名(五字中文為限)" and excel.iloc[0,2]=="人員性別(1 -> 男，2 -> 女)"):
            for x in excel.values:
                if(x[0]==excel.iloc[0,0]):
                    continue
                if (isinstance(x[0],str) and isinstance(x[1],str)):
                    model = PersonModel.FromDB(x[0], self.log.SetMessage)
                    if not model.isExist:
                        if((len(x[0])>0 and len(x[0])<11) and (len(x[1]) < 6 and len(x[1]) > 0) and (x[2] == 1 or x[2] == 2) ):
                            # 檢查ID、姓名、性別是否符合規範                        
                            model.SetName(x[1])
                            model.SetSex(x[2])
            #                 model.SetType(x[3])
                            model.SetType(2)
                            if model.InsertToDB():
                                insert.append(x[0])
                            else:
                                not_insert.append(x[0])
                        else:
                            not_insert.append(x[0])
                    else:
                        not_insert.append(x[0])
            self.message = "{0} person inserted, {1} person insert failed, {2}".format(len(insert), len(not_insert), ', '.join(not_insert))
        else:
            self.message = "File format error"
        return self.GetResponse()
# ========== 更新使用者資源 ==========
class PersonUpdate(BaseResource):
    def __init__(self):
        super().__init__("UpdatePerson")
        self.parser.add_argument('id', required=True, help="上限 10 字")
        self.parser.add_argument('name', required=True, help="上限 10 字")
        self.parser.add_argument('sex', required=True, help="1:男, 2: 女, 3:未知")
        self.parser.add_argument('type', required=True, help="1:黑名單, 2: 白名單, 3:VIP名單")
        self.parser.add_argument('token')
        self.parser.add_argument('photo', type=FileStorage, location='files')
        self.parser.add_argument('start', help="yyyy-MM-dd HH:mm:ss")
        self.parser.add_argument('end', help="yyyy-MM-dd HH:mm:ss")
        self.parser.add_argument('deleted', help="0 or 1")
    def post(self):
        args = self.parser.parse_args()
        model = PersonModel.FromDB(args['id'], self.log.SetMessage)
        if model.isExist:
            filename = "{0}.jpg".format(os.path.join("static", "person", args['id']))
            if isinstance(args['photo'], FileStorage) and bool(args['photo']):
                args['photo'].save(filename)
                model.SetPhoto(filename)
            model.SetName(args['name'])
            model.SetSex(args['sex'])
            model.SetType(args['type'])
            model.SetToken(args['token'])
            if(args['deleted']=="1"):
                d=model.GetNow()
                model.SetDeleted(d)
            else:
                model.SetDeleted("")
            # model.SetPhoto(filename)
            if model.SetStart(args['start']):
                if model.SetEnd(args['end']):
                    devices = DeviceModel.AllFromDB(self.log.SetMessage)
                    failed = []
                    for device in devices:
                        if not device.UpdateToDevice(model):
                            if device.GetType() == 5:
                                self.result = 10 if device.ResultCode == -3 else self.result
                                self.result = 11 if device.ResultCode == -15 else self.result
                                device.ResultCode = "ID 無法使用" if device.ResultCode == -3 else device.ResultCode
                                device.ResultCode = "人臉偵測失敗" if device.ResultCode == -15 else device.ResultCode
                                failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                            if device.GetType() == 4:
                                self.result = 2 if device.ResultCode == -2 else self.result
                                self.result = 1000 if device.ResultCode == -1000 else self.result
                                self.result = 1003 if device.ResultCode == -1003 else self.result
                                self.result = 1004 if device.ResultCode == -1004 else self.result
                                self.result = 2001 if device.ResultCode == -2001 else self.result
                                self.result = 2002 if device.ResultCode == -2002 else self.result
                                self.result = 2003 if device.ResultCode == -2003 else self.result
                                self.result = 2004 if device.ResultCode == -2004 else self.result
                                self.result = 2005 if device.ResultCode == -2005 else self.result
                                self.result = 2006 if device.ResultCode == -2006 else self.result
                                device.ResultCode = "沒有對應的ID資料" if device.ResultCode == -2 else device.ResultCode
                                device.ResultCode = "Undefined Errcode" if device.ResultCode == -1000 else device.ResultCode
                                device.ResultCode = "Token無效" if device.ResultCode == -1003 else device.ResultCode
                                device.ResultCode = "設備在伺服器中沒有註冊" if device.ResultCode == -1004 else device.ResultCode
                                device.ResultCode = "JSON字串轉換JavaScript數值或物件錯誤" if device.ResultCode == -2001 else device.ResultCode
                                device.ResultCode = "超過資料庫的最大數量" if device.ResultCode == -2002 else device.ResultCode
                                device.ResultCode = "無法取得Java Feature" if device.ResultCode == -2003 else device.ResultCode
                                device.ResultCode = "無效的JPG圖檔格式" if device.ResultCode == -2004 else device.ResultCode
                                device.ResultCode = "SDcard 無法讀取" if device.ResultCode == -2005 else device.ResultCode
                                device.ResultCode = "Model SDK 無法正常初始化" if device.ResultCode == -2006 else device.ResultCode
                                failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                            if device.GetType() == 2:
                                    failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                    if len(failed) == 0 or True:
                        if model.UpdateToDB(self.log.SetMessage):
                            self.message = []
                            if model.HasChangeName():
                                self.message.append(
                                    "Name: {0} -> {1}".format(model.GetOldName(), model.GetName())
                                )
                            if model.HasChangeSex():
                                self.message.append(
                                    "Sex: {0} -> {1}".format(model.GetOldSex(), model.GetSex())
                                )
                            if model.HasChangeType():
                                self.message.append(
                                    "Type: {0} -> {1}".format(model.GetOldType(), model.GetType())
                                )
                            if model.HasChangeToken():
                                self.message.append(
                                    "Token: {0} -> {1}".format(model.GetOldToken(), model.GetToken())
                                )
                            if model.HasChangeStart():
                                self.message.append(
                                    "Start: {0} -> {1}".format(model.GetOldStart(), model.GetStart())
                                )
                            if model.HasChangeEnd():
                                self.message.append(
                                    "End: {0} -> {1}".format(model.GetOldEnd(), model.GetEnd())
                                )
                            self.message = " ".join(self.message) if len(self.message) > 0 else ""
                            if len(failed) != 0 :
                                self.message = "{0}, {1}".format(" ".join(self.message) if len(self.message) > 0 else "",', '.join(failed))
                        else:
                            self.result = 10
                            self.message = "{0} update failed".format(args['id'])
                    else:
                        self.message = "{0} update failed, because device {1} upload failed".format(args['id'], ', '.join(failed))
                else:
                    self.message = "the format of end time {0} isn't match".format(args['end'])
            else:
                self.message = "the format of start time {0} isn't match".format(args['start'])
        else:
            self.result = 10
            self.message = "{0} isn't exist in database".format(args['id'])
        return self.GetResponse()
# ========== 刪除使用者資源 ==========
class PersonDelete(BaseResource):
    def __init__(self):
        super().__init__("DeletePerson")
        self.parser.add_argument('id', required=True, help="上限 10 字")
    def post(self):
        args = self.parser.parse_args()
        model = PersonModel.FromDB(args['id'], self.log.SetMessage)
        if model.isExist:
            devices = DeviceModel.AllFromDB(self.log.SetMessage)
            failed = []
            for device in devices:
                if not device.DeleteFromDevice(model):
                    if device.GetType() == 5:
                        device.ResultCode = "ID 無法使用" if device.ResultCode == -3 else device.ResultCode
                        device.ResultCode = "人臉偵測失敗" if device.ResultCode == -15 else device.ResultCode
                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                    if device.GetType() == 4:
                        self.result = 2 if device.ResultCode == -2 else self.result
                        self.result = 1000 if device.ResultCode == -1000 else self.result
                        self.result = 1003 if device.ResultCode == -1003 else self.result
                        self.result = 1004 if device.ResultCode == -1004 else self.result
                        self.result = 2001 if device.ResultCode == -2001 else self.result
                        self.result = 2002 if device.ResultCode == -2002 else self.result
                        self.result = 2003 if device.ResultCode == -2003 else self.result
                        self.result = 2004 if device.ResultCode == -2004 else self.result
                        self.result = 2005 if device.ResultCode == -2005 else self.result
                        self.result = 2006 if device.ResultCode == -2006 else self.result
                        device.ResultCode = "沒有對應的ID資料" if device.ResultCode == -2 else device.ResultCode
                        device.ResultCode = "Undefined Errcode" if device.ResultCode == -1000 else device.ResultCode
                        device.ResultCode = "Token無效" if device.ResultCode == -1003 else device.ResultCode
                        device.ResultCode = "設備在伺服器中沒有註冊" if device.ResultCode == -1004 else device.ResultCode
                        device.ResultCode = "JSON字串轉換JavaScript數值或物件錯誤" if device.ResultCode == -2001 else device.ResultCode
                        device.ResultCode = "超過資料庫的最大數量" if device.ResultCode == -2002 else device.ResultCode
                        device.ResultCode = "無法取得Java Feature" if device.ResultCode == -2003 else device.ResultCode
                        device.ResultCode = "無效的JPG圖檔格式" if device.ResultCode == -2004 else device.ResultCode
                        device.ResultCode = "SDcard 無法讀取" if device.ResultCode == -2005 else device.ResultCode
                        device.ResultCode = "Model SDK 無法正常初始化" if device.ResultCode == -2006 else device.ResultCode
                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
                    if device.GetType() == 2:
                        failed.append("{0}: {1}".format(device.GetID(), device.ResultCode))
            if len(failed) == 0 or True:
                if model.DeleteFromDB(self.log.SetMessage):
                    self.message = "{0} deleted".format(args['id'])
                    if len(failed) != 0:
                        self.message = "{0} deleted, device {1} upload failed".format(args['id'],', '.join(failed))
                else:
                    self.message = "{0} delete failed".format(args['id'])
            else:
                self.message = "{0} delete failed, because device {1} upload failed".format(args['id'], ', '.join(failed))
        else:
            self.message = "{0} isn't exist in database".format(args['id'])
        return self.GetResponse()
# ========== select person resource ==========
class PersonSelect(BaseResource):
    def __init__(self):
        super().__init__("SelectPerson")
    def get(self, ID=None):
        model = PersonModel.FromDB(ID, self.log.SetMessage)
        if model.isExist:
            file = '{0}.jpg'.format(os.path.join('static', 'person', model.GetID()))
            if not os.path.isfile(file) and model.GetPhoto()!=None:
                with open(file, 'wb') as f:
                    f.write(base64.b64decode(model.GetPhoto()))
            start = model.GetStart()
            end = model.GetEnd()
            self.data = {
                'ID': model.GetID(),
                'Name': model.GetName(),
                'Sex': model.GetSex(),
                'Type': model.GetType(),
                'Token': model.GetToken(),
                'Photo': model.GetID() if model.GetPhoto()!=None else None,
                'Start': start.strftime("%Y-%m-%d %H:%M:%S") if start is not None else None,
                'End': end.strftime("%Y-%m-%d %H:%M:%S") if end is not None else None,
                'Enabled': model.IsEnabled(),
            }
            self.message = "{0} selected".format(ID)
        else:
            self.message = "{0} isn't exist in database".format(ID)
        return self.GetResponse()
# ========== select all person resource ==========
class PersonSelectAll(BaseResource):
    def __init__(self):
        super().__init__("SelectAllPerson")
    def get(self):
        models = PersonModel.AllFromDB(self.log.SetMessage)
        if len(models) > 0:
            self.data = []
            for model in models:
                file = '{0}.jpg'.format(os.path.join('static', 'person', model.GetID()))
                if not os.path.isfile(file) and model.GetPhoto()!=None:
                    with open(file, 'wb') as f:
                        f.write(base64.b64decode(model.GetPhoto()))
                start = model.GetStart()
                end = model.GetEnd()
                self.data.append({
                    'ID': model.GetID(),
                    'Name': model.GetName(),
                    'Sex': model.GetSex(),
                    'Type': model.GetType(),
                    'Token': model.GetToken(),
                    'Photo': model.GetID() if model.GetPhoto()!=None else None,
                    'Start': start.strftime("%Y-%m-%d %H:%M:%S") if start is not None else None,
                    'End': end.strftime("%Y-%m-%d %H:%M:%S") if end is not None else None,
                    'Enabled': model.IsEnabled(),
                })
            self.message = "{0} selected".format(len(self.data))
        else:
            self.message = "no data in database"
        return self.GetResponse()
# ========== send person photo resource ==========
class PersonSend(SendBaseResource):
    def __init__(self):
        super().__init__('image/jpeg')
    def get(self, ID):
        file = "{0}.jpg".format(os.path.join('./static', 'person', ID))
        return self.GetFileResponse(file)
