# -*- coding:utf-8 -*-
"""
@Author  : xuxingchen
@Contact : xuxingchen@sinochem.com
@Desc    : 设备信息表 增&改&查
"""
import csv
import os
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, field_validator

from device.call import ServicesCall, DelFaceItem, AddFaceItem
from models.houses import HousesTable
from utils import logger
from utils.database import BaseTable, get_table_handler
from utils.misc import InvalidException, now_datetime_second, decrypt_number


class DeviceRegister(BaseModel):
    device_mac: str
    device_name: str
    device_desc: str
    third_local_device_id: str
    device_status: str = "离线"
    device_sct: Optional[str] = None
    # 以下需要查询已注册设备信息获取
    gateway_id: Optional[int] = None
    gateway_name: Optional[str] = None
    # 以下需要查询产品信息表获取
    product_name: str
    node_type: str


class Device(BaseModel):
    device_id: int
    device_name: str
    node_type: str
    product_name: str


class AccessDevice(BaseModel):
    device_id: int
    building_ids: list[str]

    @field_validator("device_id")
    def check_device_id(cls, value):
        th = get_table_handler()
        if DevicesTable.bind_exits(th, value):
            raise InvalidException(f"设备:{value} 已被添加过关联")
        if not DevicesTable.exits(th, value):
            raise InvalidException(f"设备:{value} 不存在")
        return value

    @field_validator("building_ids")
    def check_authorized_scope(cls, value):
        th = get_table_handler()
        for i in value:
            if not HousesTable.building_exists(th, i):
                raise InvalidException(f"楼栋:{i} 不存在")
        return value


class AccessDevicesScope(BaseModel):
    device_type: str
    info: List[AccessDevice]

    @field_validator("device_type")
    def check_device_type(cls, value):
        if value in ["大门闸机", "大门门禁"]:
            return value
        else:
            raise InvalidException("请提供正确的设备类型:[大门闸机, 大门门禁]")


class BuildingDevice(BaseModel):
    device_id: int
    bind_unit_id: str

    @field_validator("device_id")
    def check_device_id(cls, value):
        th = get_table_handler()
        if DevicesTable.bind_exits(th, value):
            raise InvalidException(f"设备:{value} 已被添加过关联")
        if not DevicesTable.exits(th, value):
            raise InvalidException(f"设备:{value} 不存在")
        return value

    @field_validator("bind_unit_id")
    def check_bind_unit_id(cls, value):
        th = get_table_handler()
        if not HousesTable.unit_exists(th, value):
            raise InvalidException(f"单元:{value} 不存在")
        return value


class BuildingDevicesScope(BaseModel):
    info: List[BuildingDevice]


class SearchDevicesInfo(BaseModel):
    search_type: Optional[str] = None
    search_key: Optional[str] = None

    @field_validator("search_type")
    def check_search_type(cls, value):
        types = {
            "设备名称": "device_name",
            "MAC地址": "device_mac",
            "设备ID": "device_id"
        }
        if value in types:
            return types[value]
        else:
            raise InvalidException(f"请提供正确的类型：{list(types.keys())}")


class DevicesTable(BaseTable):
    @staticmethod
    def check(table_handler: BaseTable):
        """检测是否存在当前表"""
        table_handler.query("SELECT name FROM sqlite_master WHERE type='table' AND name='devices'")
        if table_handler.cursor.fetchone() is None:
            table_handler.execute(
                f"""
                CREATE TABLE devices (
                    device_id INTEGER PRIMARY KEY AUTOINCREMENT,
                    device_mac TEXT UNIQUE,
                    device_name TEXT,
                    device_desc TEXT,
                    third_local_device_id TEXT,
                    device_status TEXT,
                    device_sct TEXT,
                    gateway_id INTEGER,
                    gateway_name TEXT,
                    product_name TEXT,
                    node_type TEXT,
                    last_online_datetime TEXT,
                    register_datetime TEXT
                )
                """
            )
        init_config_path = os.path.join(os.path.dirname(os.path.abspath("__file__")), "data/InitialData/devices.csv")
        if os.path.exists(init_config_path):
            with open(init_config_path, newline='', encoding='utf8') as csvfile:
                csvreader = csv.reader(csvfile)
                head = next(csvreader)
                data = []
                if len(head) == 12:
                    for row in csvreader:
                        device_mac = row[0].strip()
                        device_name = row[1].strip()
                        device_desc = row[2].strip() if row[2].strip() else None
                        third_local_device_id = row[3].strip() if row[3].strip() else None
                        device_status = row[4].strip() if row[4].strip() else "离线"
                        device_sct = row[5].strip() if row[5].strip() else None
                        gateway_id = int(row[6].strip()) if row[6].strip() else None
                        gateway_name = row[7].strip() if row[7].strip() else None
                        product_name = row[8].strip()
                        node_type = row[9].strip()
                        last_online_datetime = row[10].strip() if row[10].strip() else None
                        register_datetime = row[11].strip() if row[11].strip() else None
                        data.append((device_mac, device_name, device_desc, third_local_device_id, device_status,
                                     device_sct, gateway_id, gateway_name, product_name, node_type,
                                     last_online_datetime, register_datetime))
                    table_handler.executemany(
                        f"""
                        INSERT INTO devices 
                        (device_mac, device_name, device_desc, third_local_device_id, device_status,
                        device_sct, gateway_id, gateway_name, product_name, node_type,
                        last_online_datetime, register_datetime) 
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
                        ON CONFLICT (device_mac) DO NOTHING
                        """,
                        data
                    )

        table_handler.query("SELECT name FROM sqlite_master WHERE type='table' AND name='devices_scope'")
        if table_handler.cursor.fetchone() is None:
            table_handler.execute(
                f"""
                CREATE TABLE devices_scope (
                    device_id INT,
                    device_type TEXT,
                    bind_unit_id TEXT,
                    UNIQUE (device_id, bind_unit_id)
                )
                """
            )
        init_config_path = os.path.join(os.path.dirname(os.path.abspath("__file__")),
                                        "data/InitialData/devices_scope.csv")
        if os.path.exists(init_config_path):
            with open(init_config_path, newline='', encoding='utf8') as csvfile:
                csvreader = csv.reader(csvfile)
                head = next(csvreader)
                data = []
                if len(head) == 3:
                    for row in csvreader:
                        device_id = row[0].strip()
                        device_type = row[1].strip()
                        bind_unit_id = row[2].strip()
                        data.append((device_id, device_type, bind_unit_id))
                    table_handler.executemany(
                        f"""
                        INSERT INTO devices_scope 
                        (device_id, device_type, bind_unit_id) 
                        VALUES (?, ?, ?) 
                        ON CONFLICT (device_id, bind_unit_id) DO NOTHING
                        """, data
                    )

        table_handler.query("SELECT name FROM sqlite_master WHERE type='table' AND name='devices_auth'")
        if table_handler.cursor.fetchone() is None:
            table_handler.execute(
                f"""
                CREATE TABLE devices_auth (
                    device_id INT,
                    _id TEXT,
                    record_type TEXT,
                    start_date TEXT,
                    expire_date TEXT,
                    add_datetime TEXT,
                    update_datetime TEXT,
                    UNIQUE (device_id, _id, record_type)
                )
                """
            )

        init_config_path = os.path.join(os.path.dirname(os.path.abspath("__file__")),
                                        "data/InitialData/devices_auth.csv")
        if os.path.exists(init_config_path):
            with open(init_config_path, newline='', encoding='utf8') as csvfile:
                csvreader = csv.reader(csvfile)
                head = next(csvreader)
                data = []
                if len(head) == 5:
                    for row in csvreader:
                        device_id = row[0].strip()
                        _id = row[1].strip()
                        record_type = row[2].strip()
                        start_date = row[3].strip()
                        expire_date = row[4].strip()
                        data.append((device_id, _id, record_type, start_date, expire_date,
                                     now_datetime_second(), now_datetime_second()))
                    table_handler.executemany(
                        f"""
                        INSERT INTO devices_auth 
                        (device_id, _id, record_type, start_date, expire_date, add_datetime, update_datetime) 
                        VALUES (?, ?, ?, ?, ?, ?, ?) 
                        ON CONFLICT (device_id, _id, record_type) DO NOTHING
                        """, data
                    )

    @staticmethod
    def insert_by_device_register(table_handler: BaseTable, obj: DeviceRegister):
        register_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        table_handler.execute(
            """
            INSERT INTO devices 
            (device_mac, device_name, device_desc, third_local_device_id, device_status, device_sct, 
            gateway_id, gateway_name, product_name, node_type, register_datetime)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON CONFLICT (device_mac) DO UPDATE SET 
            device_name=?, device_desc=?, third_local_device_id=?, 
            device_status=?, device_sct=?, gateway_id=?, gateway_name=?, 
            product_name=?, node_type=?, register_datetime=?
            """,
            (obj.device_mac, obj.device_name, obj.device_desc, obj.third_local_device_id,
             obj.device_status, obj.device_sct, obj.gateway_id, obj.gateway_name,
             obj.product_name, obj.node_type, register_datetime,
             obj.device_name, obj.device_desc, obj.third_local_device_id,
             obj.device_status, obj.device_sct, obj.gateway_id, obj.gateway_name,
             obj.product_name, obj.node_type, register_datetime)
        )
        table_handler.query(
            """
            SELECT device_id
            FROM devices
            WHERE device_mac = ?
            """,
            (obj.device_mac,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return res[0][0]
        return None

    @staticmethod
    def insert_device_auth_record(table_handler: BaseTable, device_id: int, _id: str,
                                  start_date: str, expire_date: str, record_type: str = '人行'):
        table_handler.execute(
            """
            INSERT INTO devices_auth 
            (device_id, _id, record_type, start_date, expire_date, add_datetime, update_datetime)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            ON CONFLICT (device_id, _id, record_type) DO UPDATE SET 
            start_date=?, expire_date=?, update_datetime=?
            """,
            (device_id, _id, record_type, start_date, expire_date,
             now_datetime_second(), now_datetime_second(), start_date, expire_date, now_datetime_second())
        )

    @staticmethod
    def get_devices_info(table_handler: BaseTable):
        """获取对应设备的基本信息"""
        table_handler.query(
            """
            SELECT device_name, third_local_device_id, device_id, device_status, 
            gateway_name, product_name, node_type, last_online_datetime, register_datetime
            FROM devices
            WHERE node_type != '网关设备'
            """
        )
        res = table_handler.cursor.fetchall()
        if res:
            devices_info = []
            for item in res:
                devices_info.append({
                    "device_name": item[0],
                    "third_local_device_id": item[1],
                    "device_id": item[2],
                    "device_status": item[3],
                    "gateway_name": item[4] if item[4] else "",
                    "product_name": item[5],
                    "node_type": item[6],
                    "last_online_datetime": item[7] if item[7] else "",
                    "register_datetime": item[8]
                })
            return devices_info
        return None

    @staticmethod
    def get_device_info(table_handler: BaseTable, device_id: int):
        """获取对应设备的基本信息"""
        table_handler.query(
            """
            SELECT device_name, node_type, product_name
            FROM devices
            WHERE device_id = ?
            """,
            (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return Device(device_id=device_id, device_name=res[0][0], node_type=res[0][1], product_name=res[0][2])
        return None

    @staticmethod
    def get_device_name(table_handler: BaseTable, device_id: int):
        """获取对应设备名"""
        table_handler.query(
            """
            SELECT device_name
            FROM devices
            WHERE device_id = ?
            """,
            (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return res[0][0]
        return ""

    @staticmethod
    def get_device_scope_type(table_handler: BaseTable, device_id: int):
        """获取对应设备门禁类型"""
        table_handler.query(
            """
            SELECT device_type
            FROM devices_scope
            WHERE device_id = ?
            """,
            (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return res[0][0]
        return ""

    @staticmethod
    def get_device_ids_by_unit_id(table_handler: BaseTable, unit_id: str) -> list:
        """查询对应单元权限内的设备ID"""
        table_handler.query(
            """
            SELECT GROUP_CONCAT(device_id) AS device_ids
            FROM devices_scope
            WHERE bind_unit_id = ?
            """, (unit_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return res[0][0].split(',')
        else:
            return []

    @staticmethod
    def get_device_ids(table_handler: BaseTable, filter_name: Optional[str] = None, filter_online: bool = True):
        """获取相关的设备ID"""
        sub_sql_list = []
        if filter_online:
            sub_sql_list.append("device_status = '在线'")
        if filter_name is not None:
            sub_sql_list.append(f"product_name like '%{filter_name}%'")
        if len(sub_sql_list) > 0:
            sub_sql = "WHERE " + " AND ".join(sub_sql_list)
        else:
            sub_sql = ""
        table_handler.query(f"SELECT GROUP_CONCAT(device_id) device_ids FROM devices {sub_sql}")
        res = table_handler.cursor.fetchall()
        if res:
            return [i for i in res[0][0].split(',')]
        else:
            return []

    @staticmethod
    def get_auth_interval(table_handler: BaseTable, _id: str, device_id: int, record_type: str = '人行'):
        """获取对应ID授权在设备上的有效期"""
        table_handler.query(
            """
            SELECT start_date, expire_date
            FROM devices_auth
            WHERE device_id = ? and _id = ? and record_type = ?
            """,
            (device_id, _id, record_type)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return res[0][0], res[0][1]
        return "", ""

    @staticmethod
    def update_device_status(table_handler: BaseTable, device_id: int, device_status: str):
        """更新设备在线状态"""
        if device_status == "在线":
            last_online_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            set_sql = f"device_status='在线', last_online_datetime='{last_online_datetime}' "
        else:
            set_sql = f"device_status='离线' "
        table_handler.execute(
            f"""
            UPDATE devices SET {set_sql}
            WHERE device_id={device_id}
            """
        )

    @staticmethod
    def offline_gateway(table_handler: BaseTable, device_id: int):
        """用于在网关下线时同时下线网关下的所有设备"""
        table_handler.execute(
            f"""
            UPDATE devices SET device_status='离线' 
            WHERE device_id={device_id} or gateway_id={device_id}
            """
        )

    @staticmethod
    def get_access_devices_info(table_handler: BaseTable,
                                is_associated: bool,
                                device_name: str = None,
                                product_name: str = None,
                                device_mac: str = None,
                                device_id: int = None):
        if is_associated:
            sub_sql = "WHERE d.node_type != '网关设备' AND product_name not like '%停车场%' AND device_type is not null "
        else:
            sub_sql = "WHERE d.node_type != '网关设备' AND product_name not like '%停车场%' AND device_type is null "
        if device_name:
            sub_sql += f"AND device_name = '{device_name}'"
        elif product_name:
            sub_sql += f"AND product_name = '{product_name}'"
        elif device_mac:
            sub_sql += f"AND device_mac = '{device_mac}'"
        elif device_id:
            sub_sql += f"AND d.device_id = {device_id}"
        table_handler.query(
            f"""
            SELECT
                d.device_id,
                device_name,
                device_mac,
                device_status,
                ds.device_type,
                GROUP_CONCAT(t.building_name || '-' || t.unit_name) as scopes,
                product_name
            FROM devices d
            LEFT JOIN devices_scope ds ON ds.device_id = d.device_id
            LEFT JOIN (SELECT DISTINCT unit_id, unit_name, building_id, building_name FROM houses) t 
            ON t.unit_id = ds.bind_unit_id
            {sub_sql}
            GROUP BY d.device_id, device_name, device_mac, device_status, ds.device_type, product_name
            """
        )
        res = table_handler.cursor.fetchall()
        if res:
            devices_info = []
            for i in res:
                devices_info.append({
                    "device_id": i[0],
                    "device_name": i[1],
                    "device_mac": i[2],
                    "device_status": i[3],
                    "device_type": i[4] if i[4] else "",
                    "authorized_scope": i[5].split(",") if i[5] else [],
                    "product_name": i[6]
                })
            return {"devices": devices_info}
        return {"devices": []}

    @staticmethod
    def get_associated_access_devices_info(table_handler: BaseTable,
                                           search_type: Optional[str] = None,
                                           search_key: Optional[str] = None):
        if search_type:
            if search_type == "device_id":
                sub_sql = f"WHERE ds.device_id = {search_key}"
            elif search_type == "device_name":
                sub_sql = f"WHERE d.device_name like '%{search_key}%'"
            else:
                sub_sql = f"WHERE d.{search_type} = '{search_key}'"
        else:
            sub_sql = ""
        table_handler.query(
            f"""
            SELECT ds.device_id as _id,
                   d.device_name as _name,
                   d.device_mac as _mac,
                   d.device_status as _status
            FROM (SELECT DISTINCT device_id FROM devices_scope) ds
                LEFT JOIN devices d ON ds.device_id = d.device_id
            {sub_sql}
            """
        )
        res = table_handler.cursor.fetchall()
        if res:
            devices_info = []
            for i in res:
                devices_info.append({
                    "device_id": i[0],
                    "device_name": i[1],
                    "device_mac": i[2],
                    "device_status": i[3]
                })
            return {"devices": devices_info}
        return {"devices": []}

    @staticmethod
    def auto_auth_by_unit_id(table_handler: BaseTable, device_id: int, unit_id: str):
        """查询对应单元下相关住户，对具备人脸的住户授权"""
        table_handler.query(
            """
            SELECT h.householder_id, name, phone, face_url
            FROM householders h
            LEFT JOIN householders_type ht ON ht.householder_id=h.householder_id
            LEFT JOIN houses ON ht.room_id=houses.room_id
            WHERE h.type = '住户' AND (face_url != '' or face_url is not null ) AND houses.unit_id = ?
            """, (unit_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            # 人员人脸下放
            for i in res:
                sc = ServicesCall()
                face_item = AddFaceItem(
                    user_id=i[0],
                    name=i[1],
                    phone_number=decrypt_number(i[2]),
                    face_url=i[3],
                    device_ids=str([device_id])
                )
                _callback, code, msg = sc.add_face(device_id, face_item)
                if _callback:
                    DevicesTable.insert_device_auth_record(table_handler, device_id, face_item.user_id,
                                                           face_item.start_date, face_item.expire_date)

    @staticmethod
    def add_access_devices(table_handler: BaseTable, device_type: str, objs: List[AccessDevice]):
        data = []
        for obj in objs:
            for bind_building_id in obj.building_ids:
                unit_ids = HousesTable.get_unit_ids(table_handler, bind_building_id)
                for unit_id in unit_ids:
                    data.append((obj.device_id, device_type, unit_id, device_type))
                    DevicesTable.auto_auth_by_unit_id(table_handler, obj.device_id, unit_id)
        try:
            table_handler.executemany(
                """
                INSERT INTO devices_scope
                (device_id, device_type, bind_unit_id)
                VALUES (?, ?, ?)
                ON CONFLICT (device_id, bind_unit_id) DO UPDATE
                SET device_type = ?
                """, data
            )
            return True
        except Exception as e:
            logger.Logger.error(f"DevicesTable.add_access_devices: {type(e).__name__}, {e}")
            raise InvalidException(f"DevicesTable.add_access_devices: {type(e).__name__}, {e}")

    @staticmethod
    def add_building_devices(table_handler: BaseTable, device_type: str, objs: List[BuildingDevice]):
        data = []
        for obj in objs:
            data.append((obj.device_id, device_type, obj.bind_unit_id))
            DevicesTable.auto_auth_by_unit_id(table_handler, obj.device_id, obj.bind_unit_id)
        try:
            table_handler.executemany(
                """
                INSERT INTO devices_scope
                (device_id, device_type, bind_unit_id)
                VALUES (?, ?, ?)
                ON CONFLICT (device_id, bind_unit_id) DO NOTHING
                """, data
            )
            return True
        except Exception as e:
            logger.Logger.error(f"DevicesTable.add_building_devices: {type(e).__name__}, {e}")
            return False

    @staticmethod
    def add_update_device_auth(table_handler: BaseTable, device_id, _ids: list[str], record_type: str,
                               start_date: str, expire_date: str):
        """对应设备批量授权记录增加"""
        data = []
        for _id in _ids:
            _datetime = now_datetime_second()
            data.append((device_id, _id, record_type, start_date, expire_date, _datetime, _datetime,
                         start_date, expire_date, _datetime))
        try:
            table_handler.executemany(
                """
                INSERT INTO devices_auth
                (device_id, _id, record_type, start_date, expire_date, add_datetime, update_datetime)
                VALUES (?, ?, ?, ?, ?, ?, ?)
                ON CONFLICT (device_id, _id, record_type)
                DO UPDATE SET start_date = ?, expire_date = ?, update_datetime = ?
                """, data
            )
            return True
        except Exception as e:
            logger.Logger.error(f"DevicesTable.add_device_auth: {type(e).__name__}, {e}")
            return False

    @staticmethod
    def get_auth_device_ids(table_handler: BaseTable, _id: str, record_type: str = '人行'):
        """获取ID的所有授权设备"""
        table_handler.query(
            """
            SELECT device_id
            FROM devices_auth
            WHERE _id = ? AND record_type = ?
            """, (_id, record_type)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return [i[0] for i in res]
        else:
            return []

    @staticmethod
    def get_auth_device_info(table_handler: BaseTable, _id: str, record_type: str = '人行'):
        """获取ID当前所有授权设备基础信息"""
        table_handler.query(
            """
            SELECT devices_auth.device_id, device_name, device_mac, device_status
            FROM devices_auth
            LEFT JOIN devices ON devices.device_id = devices_auth.device_id
            WHERE _id = ? AND record_type = ?
            """, (_id, record_type)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return [{"device_id": i[0], "device_name": i[1], "device_mac": i[2], "device_status": i[3]} for i in res]
        else:
            return []

    @staticmethod
    def get_auth_householders_info(table_handler: BaseTable, device_id: int):
        """获取关联授权下的所有完成下放的人员信息"""
        table_handler.query(
            """
            SELECT da._id, name, phone, face_url, da.start_date, da.expire_date
            FROM devices_auth da
                     LEFT JOIN householders h ON da._id = h.householder_id
            WHERE device_id = ? AND record_type = '人行'
            """, (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return [{"id": i[0], "name": i[1], "phone": i[2], "url": i[3], "sdate": i[4], "edate": i[5]} for i in res]
        else:
            return []

    @staticmethod
    def delete_householder_all_auth(table_handler: BaseTable, _id: str):
        table_handler.execute(
            """
            DELETE FROM devices_auth
            WHERE _id = ? AND record_type = '人行'
            """, (_id,)
        )

    @staticmethod
    def delete_invalid_auth_record(table_handler: BaseTable, device_id: int, _id: str, record_type: str = '人行'):
        table_handler.execute(
            """
            DELETE FROM devices_auth 
            WHERE device_id = ? AND _id = ? AND record_type = ?
            """,
            (device_id, _id, record_type)
        )

    @staticmethod
    def delete_access_device_info(table_handler: BaseTable, device_id: int):
        # 1. 确认设备ID有效
        if not DevicesTable.exits(table_handler, device_id):
            raise InvalidException(f"设备:{device_id} 不存在")
        # 2. 获取关联授权下的所有完成下放的人员信息
        householder_infos = DevicesTable.get_auth_householders_info(table_handler, device_id)
        if len(householder_infos) > 0:
            # 3. 移除对应设备中所有的人员信息
            sc = ServicesCall()
            success_ids = []
            for index, householder_info in enumerate(householder_infos):
                _callback, code, _ = sc.del_face(device_id,
                                                 DelFaceItem(user_id=str(householder_info["id"]),
                                                             device_ids=str([device_id])))
                if not _callback:
                    # 存在异常时，回滚已删除掉的人脸
                    failed = []
                    msgs = []
                    for success_id in success_ids:
                        _back, code, msg = sc.add_face(device_id, AddFaceItem(
                            name=householder_infos[success_id]["name"],
                            user_id=str(householder_infos[success_id]["id"]),
                            phone_number=householder_infos[success_id]["phone"],
                            face_url=householder_infos[success_id]["url"],
                            device_ids=str([device_id]),
                            start_date=householder_infos[success_id]["sdate"],
                            expire_date=householder_infos[success_id]["edate"]
                        ))
                        if not _back:
                            failed.append(householder_infos[success_id]["id"])
                            msgs.append(msg)
                    if len(failed) == 0:
                        raise InvalidException(
                            f"住户 - {householder_info['id']} 人脸授权移除失败，错误码{code}, {msgs}, 已完成回滚")
                    else:
                        raise InvalidException(
                            f"住户 - {householder_info['id']} 人脸授权移除失败，错误码{code}, {msgs}, 回滚失败")
                success_ids.append(index)
        # 4. 移除设备的关联记录
        table_handler.execute(
            """
            DELETE FROM devices_auth
            WHERE device_id = ? AND record_type = '人行'
            """, (device_id,)
        )
        table_handler.execute(
            """
            DELETE FROM devices_scope
            WHERE device_id = ? 
            """, (device_id,)
        )
        return {"status": True}

    @staticmethod
    def exits(table_handler: BaseTable, device_id: int):
        table_handler.query(
            """
            SELECT device_id FROM devices
            WHERE device_id = ?
            """, (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return True
        else:
            return False

    @staticmethod
    def bind_exits(table_handler: BaseTable, device_id: int):
        table_handler.query(
            """
            SELECT bind_unit_id 
            FROM devices_scope
            WHERE device_id = ?
            """, (device_id,)
        )
        res = table_handler.cursor.fetchall()
        if res:
            return True
        else:
            return False
