# -*- coding: utf-8 -*-

import sqlite3
import json
import os
import webview
import pickle
import re
import time
from datetime import datetime
# 假设 get_cookie 函数在这个文件中
# 确保 获取cookie.py 文件已更新，特别是清理 '|' 字符的部分
from 获取cookie import get_cookie  # 导入 get_cookie 函数
import requests
from 拉黑 import DouyinLiveWebFetcher, update_global_settings, jclahei
import sys
import threading


session = requests.session()


# 注意：这里不再需要 COOKIE_FILE = 'cookies.pkl'，因为每个账号对应一个文件

# 定义从 cookie_name.txt 文件读取账号数据的函数
def read_accounts_from_file():
    """从 cookie_name.txt 逐行读取账号数据，返回字典列表。"""
    accounts = []
    # 检查文件是否存在，如果不存在则返回空列表
    if not os.path.isfile('cookie_name.txt'):
        print('read_accounts_from_file: 未找到 cookie_name.txt 文件。')
        return accounts

    try:
        # 以文本模式打开文件，Python 会自动处理不同换行符
        with open('cookie_name.txt', 'r', encoding='utf-8') as f:
            seen_urls = set()  # 用于跟踪已添加的账号 URL 部分，避免重复添加

            # 逐行读取文件
            for line_num, raw_line in enumerate(f, 1):  # 从 1 开始计数行号
                stripped_line = raw_line.strip()  # 移除行首尾的空白字符（包括各种换行符）

                if not stripped_line:  # 跳过空行
                    continue

                # print(f"read_accounts_from_file: 处理第 {line_num} 行: '{stripped_line}'") # 调试输出每条有效行

                parts = stripped_line.split('|')

                if len(parts) == 3:
                    url_part, nickname, douyin_id = parts
                    # 如果 url_part 未见过，则添加
                    if url_part not in seen_urls:
                        accounts.append({
                            'url_part': url_part,
                            'nickname': nickname,
                            'douyin_id': douyin_id,
                            # 添加过期时间占位符 - 之后替换为实际逻辑
                            'expiry_time': '25年06月06日21时32分'  # 硬编码的到期时间
                        })
                        seen_urls.add(url_part)
                        # print(f"read_accounts_from_file: 添加账号: url_part='{url_part}'") # 调试输出添加的账号
                    # else:
                    # print(f"read_accounts_from_file: 跳过重复账号 (url_part): '{url_part}'") # 调试输出跳过的重复账号
                else:
                    print(
                        f"read_accounts_from_file: 跳过格式错误的第 {line_num} 行 (部分数量 != 3): '{stripped_line}'")  # 调试输出格式错误的行

    except Exception as e:
        print(f"read_accounts_from_file: 读取或解析 cookie_name.txt 时出错: {e}")
        # 错误时返回空列表
        return []

    print(f"read_accounts_from_file: 成功解析 {len(accounts)} 个账号。")
    # print("read_accounts_from_file: 解析后的账号列表:", accounts) # 调试输出最终账号列表
    return accounts


# 读取cookie pkl文件
def load_cookies_from_file(filename):
    # 以二进制写入模式打开文件

    with open(filename, 'rb') as f:
        return pickle.load(f)


def get_roomId(url, Cookie):
    print(datetime.now(), '正在请求直播房间')
    headers = {
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
    }
    for _ in range(10):
        res = session.get(url, headers=headers, cookies=Cookie)
        # print(res.text)
        roomId = re.findall(r'\\"roomId\\":\\"(\d+?)\\"', res.text) if re.findall(r'\\"roomId\\":\\"(\d+?)\\"',
                                                                                  res.text) else ''
        if not roomId:
            roomId = re.findall(r'\\"roomIdStr\\":\\"(\d+?)\\"', res.text) if re.findall(
                r'\\"roomIdStr\\":\\"(\d+?)\\"',
                res.text) else ''

        if roomId:
            return roomId
        time.sleep(2)




class Api:


    # ... (如果不需要 get_localStorage 方法可以删除或保留，保持不变)
    def get_localStorage(self, data):
        # print(data)
        if not os.path.exists(json_path):
            open(json_path, 'w', encoding='utf-8').close()
        else:
            # 写入配置文件
            with open(json_path, 'w', encoding='utf-8') as f:
                f.write(data)
            # print(data)
            update_global_settings(data)

    # def get_path(self,path,path_json):
    #     root_path = os.getcwd()
    #     is_pack = getattr(sys, 'frozen', False)
    #     if is_pack:
    #         run_path = sys._MEIPASS
    #     else:
    #         run_path = root_path
    #     path = os.path.join(run_path, 'index', 'user_Settings_Options.json')
    #     return path
    # 触发登录流程并更新界面中的账号列表。
    def login_click(self):
        """触发登录流程并更新界面中的账号列表。"""
        print('执行登录流程...')
        try:
            # get_cookie 函数负责打开浏览器、登录、保存 cookie 并更新 cookie_name.txt
            # 它也应该负责将 cookie 数据保存到对应的 url_part.pkl 文件中
            # 成功返回 True，失败返回 False 或抛出异常（由于重试）
            success = get_cookie()  # 调用 获取cookie.py 中的函数

            if success:
                print('登录流程成功，正在刷新界面账号列表...')
                # 登录成功并文件更新后，刷新界面列表
                self.refresh_accounts()  # 使用 self 调用类中的另一个方法
                return True  # 指示登录流程已成功启动（不保证界面刷新已完成）
            else:
                print('登录流程失败。')
                # （可选）通知前端失败
                # window.evaluate_js('alert("登录失败，请重试。")')
                return False  # 指示登录流程失败

        except Exception as e:
            print(f'登录流程发生错误: {e}')
            if '与页面的连接已断开' in str(e):
                print('用户取消登录')
                return False
            # （可选）通知前端出错
            # window.evaluate_js(f'alert("登录发生错误: {e}")')
            return False  # 指示登录流程因错误失败

    # 从文件读取账号并发送到前端刷新表格。
    def refresh_accounts(self):
        """从文件读取账号并发送到前端刷新表格。"""
        print("正在刷新账号列表...")
        accounts = read_accounts_from_file()
        print(f"refresh_accounts: 读取到 {len(accounts)} 个账号，发送到前端。")
        # 将账号数据发送到 JavaScript 函数 updateAccountTable
        # 使用 json.dumps 将字典列表序列化为 JSON 字符串
        # 确保 JS 函数 updateAccountTable 存在并准备好接收此数据
        # 'window' 在 pywebview 的 Api 方法上下文中自动可用
        window.evaluate_js(f'updateAccountTable({json.dumps(accounts)})')
        print("refresh_accounts: 已发送账号数据到前端进行刷新。")

    # 页面加载时由 JS 调用，获取初始账号列表。
    def get_initial_accounts(self):
        """页面加载时由 JS 调用，获取初始账号列表。"""
        print("前端请求获取初始账号列表...")
        self.refresh_accounts()  # 只需调用 refresh_accounts 进行读取和发送

    # --- 新增 删除账号方法 ---
    def delete_account(self, url_part):
        """
        删除指定 url_part 的账号信息及其对应的 cookie 数据文件。
        参数: url_part (str) - 要删除账号的 url_part (例如 '76861274466')
        返回: bool - 成功删除任一文件返回 True, 都未找到返回 False
        """
        print(f"Api: 接收到删除请求，url_part: {url_part}")
        account_found_in_txt = False
        cookie_file_deleted = False

        try:
            # 1. 删除 cookie_name.txt 中的对应行
            lines_to_keep = []
            txt_file_exists = os.path.isfile('cookie_name.txt')

            if txt_file_exists:
                try:
                    with open('cookie_name.txt', 'r', encoding='utf-8') as f:
                        for line in f:
                            stripped_line = line.strip()
                            if stripped_line:
                                parts = stripped_line.split('|')
                                # 检查第一个部分是否与要删除的 url_part 匹配
                                if len(parts) >= 1 and parts[0] == url_part:
                                    print(f"Api: 在 cookie_name.txt 中找到并标记删除行: '{stripped_line}'")
                                    account_found_in_txt = True
                                else:
                                    lines_to_keep.append(line)  # 保留不匹配的行 (包括原始换行符)

                    # 如果找到了要删除的行，则重写文件
                    if account_found_in_txt:
                        with open('cookie_name.txt', 'w', encoding='utf-8') as f:
                            f.writelines(lines_to_keep)
                        print(f"Api: 已从 cookie_name.txt 中删除 url_part 为 {url_part} 的行并重写文件。")
                    else:
                        print(f"Api: 未在 cookie_name.txt 中找到 url_part 为 {url_part} 的行。")
                except Exception as e:
                    print(f"Api: 处理 cookie_name.txt 文件时发生错误: {e}")
            else:
                print(f"Api: 文件 cookie_name.txt 不存在，跳过文本文件删除。")

            # 2. 删除对应的 .pkl 文件
            pkl_filename = f'{url_part}.pkl'  # 根据 url_part 构建文件名
            pkl_file_exists = os.path.isfile(pkl_filename)

            if pkl_file_exists:
                try:
                    os.remove(pkl_filename)
                    cookie_file_deleted = True
                    print(f"Api: 已删除 cookie 文件: {pkl_filename}")
                except Exception as e:
                    print(f"Api: 删除文件 {pkl_filename} 时出错: {e}")
            else:
                print(f"Api: 未找到 cookie 文件: {pkl_filename}，跳过文件删除。")

            # 判断是否至少在一个地方（文本文件或pkl文件）进行了删除操作
            success = account_found_in_txt or cookie_file_deleted
            if success:
                print(f"Api: url_part 为 {url_part} 的账号删除处理完成。")
            else:
                print(f"Api: url_part 为 {url_part} 的账号未在任何文件中找到。")


        except Exception as e:
            # 捕获其他可能的异常
            print(f"Api: 删除账号 {url_part} 时发生总体错误: {e}")
            success = False

        # 前端会根据返回的 success 标志来决定是否调用 refreshTable()
        return success

    # --- 如果以后需要，添加其他操作方法 ---

    # 监控账号
    def monitor_account(self, url_part, username):
        print(f"正在监控 url_part 为 {url_part} 的账号")

        user_name = username
        Cookie = load_cookies_from_file(f'{url_part}.pkl')
        cookies_dict = {c.name: c.value for c in Cookie}
        cookie_str = "; ".join(f"{k}={v}" for k, v in cookies_dict.items())
        url = 'https://www.douyin.com/user/self?from_tab_name=live'  # 主播主页
        print(f'进入')
        headers = {
            'Connection': 'keep-alive',
            'Pragma': 'no-cache',
            'Cache-Control': 'no-cache',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9',
        }
        res = session.get(url, headers=headers, cookies=Cookie)
        print('开始第一次请求')

        while True:
            if not res.status_code == 200:
                print(datetime.now(), '请求失败，重试一次')
                # app_edit(f'{datetime.now()}----请求失败，重试一次')

            # 循环查询是否有开播的信息
            res = session.get(url, headers=headers, cookies=Cookie)
            if 'const verify_data' in res.text:
                print('进入直播中 const verify_data')
                print(datetime.now(), f'{user_name}--Cookie失效')
                return False  # 返回失败状态

            if '直播中</span>' in res.text:
                print('进入直播中')
                zburl = re.findall(r'<a href="(https://live.douyin.com/.*?)(?:\?action|")', res.text)
                print(zburl)
                if zburl and len(zburl) > 1:  # 确保有有效的直播链接
                    print(datetime.now(), f'{user_name}--检查到已开播')
                    roomId = get_roomId(zburl[1], Cookie)
                    print(roomId)

                    # 使用线程运行直播抓取逻辑，避免阻塞
                    def run_live_fetcher():
                        try:
                            douyin = DouyinLiveWebFetcher(zburl[1], roomId[0], cookie_str, url_part)
                            douyin.start()
                        except Exception as e:
                            print(f"直播抓取过程中出错: {e}")

                    live_thread = threading.Thread(target=run_live_fetcher)
                    live_thread.daemon = True  # 设置为守护线程，主程序退出时自动结束
                    live_thread.start()
                    print('返回')
                    return True  # 立即返回成功状态给前端
                else:
                    print("未找到有效的直播链接")
                    return False  # 返回失败状态

            time.sleep(2)
            print(datetime.now(), f'{user_name}--未直播等待2秒后再次查询')



    # 新增：从数据库获取拉黑记录的方法
    def get_blacklist_records(self, account_url_part):
        """
        从数据库获取指定主播账号的拉黑记录。
        参数: account_url_part (str) - 主播账号的 url_part
        返回: str - 拉黑记录列表的 JSON 字符串
        """
        print(f"Api: 接收到获取拉黑记录请求，账号 url_part: {account_url_part}")  # 调试打印
        conn = None
        records = []
        try:
            # 使用与主程序相同的数据库路径
            root_path = os.getcwd()
            is_pack = getattr(sys, 'frozen', False)
            if is_pack:
                run_path = sys._MEIPASS
            else:
                run_path = root_path
            blacklist_records_path = os.path.join(run_path, 'blacklist_records.db')

            conn = sqlite3.connect(blacklist_records_path)
            c = conn.cursor()

            # 查询指定账号的拉黑记录，按拉黑时间倒序排列
            # 注意：这里假设数据库字段名和前端期望的字段名映射关系
            c.execute("""
                      SELECT id,
                             user_sid,
                             user_douyin_id,
                             user_nickname,
                             user_avatar,
                             blacklist_reason,
                             blacklist_time
                      FROM blacklist_records
                      WHERE account_url_part = ?
                      ORDER BY blacklist_time DESC
                      """, (account_url_part,))

            # 将查询结果转换为前端期望的字典格式
            rows = c.fetchall()
            for row in rows:
                records.append({
                    'id': row[0],  # 数据库的 id
                    'userId': row[1],  # user_sid 映射到前端的 userId
                    'douyinId': row[2],  # user_douyin_id 映射到前端的 douyinId
                    'nickname': row[3],  # user_nickname 映射到前端的 nickname
                    'avatar': row[4],  # user_avatar 映射到前端的 avatar
                    'reason': row[5],  # blacklist_reason 映射到前端的 reason
                    'time': row[6]  # blacklist_time 映射到前端的 time
                })

            print(f"Api: 查询到 {len(records)} 条拉黑记录。")  # 调试打印

        except sqlite3.Error as e:
            print(f"Api: 数据库查询错误: {e}")  # 错误打印
            # 发生错误时返回空列表或错误指示
            records = []  # 确保发生错误时返回空列表

        except Exception as e:
            print(f"Api: 获取拉黑记录时发生未知错误: {e}")  # 错误打印
            records = []  # 确保发生错误时返回空列表

        finally:
            if conn:
                conn.close()

        # 返回 JSON 字符串
        return json.dumps(records)

    # 新增方法：强制从数据库刷新拉黑记录并更新缓存
    def refresh_blacklist_records(self, account_url_part):
        """
        强制从数据库刷新指定主播账号的拉黑记录，更新缓存，并返回最新数据。
        参数: account_url_part (str) - 主播账号的 url_part
        返回: str - 拉黑记录列表的 JSON 字符串
        """
        print(f"Api: 接收到强制刷新拉黑记录请求，账号 url_part: {account_url_part}")  # 调试打印
        # 设置强制刷新标志
        self._force_refresh = True
        # 调用 get_blacklist_records，由于设置了标志，它会从数据库读取
        return self.get_blacklist_records(account_url_part)

    # 新增方法：根据记录ID从数据库删除拉黑记录
    def delete_blacklist_record_by_id(self, record_id):
        """
        根据数据库记录ID删除单条拉黑记录。
        参数: record_id (str) - 要删除的拉黑记录的数据库ID
        返回: bool - 删除成功返回 True，失败返回 False
        """
        print(f"Api: 接收到删除单条拉黑记录请求，记录ID: {record_id}")  # 调试打印
        conn = None
        try:
            root_path = os.getcwd()
            is_pack = getattr(sys, 'frozen', False)
            if is_pack:
                run_path = sys._MEIPASS
            else:
                run_path = root_path
            blacklist_records_path = os.path.join(run_path, 'blacklist_records.db')

            conn = sqlite3.connect(blacklist_records_path)
            c = conn.cursor()

            # 执行删除操作
            c.execute("DELETE FROM blacklist_records WHERE id = ?", (record_id,))
            conn.commit()

            # 检查是否删除了记录
            deleted_count = c.rowcount
            print(f"Api: 删除拉黑记录 (ID: {record_id})。影响行数: {deleted_count}")  # 调试打印

            # 如果使用后端缓存，删除记录后需要更新缓存
            # TODO: 根据删除的 record_id 找到对应的 account_url_part，并更新 self._blacklist_cache
            # 这需要从数据库中查询 record_id 对应的 account_url_part，或者修改前端传入 account_url_part

            return deleted_count > 0  # 如果删除了至少一行，返回 True

        except sqlite3.Error as e:
            print(f"Api: 数据库删除错误 (ID: {record_id}): {e}")  # 错误打印
            return False  # 数据库错误返回 False

        except Exception as e:
            print(f"Api: 删除拉黑记录 (ID: {record_id}) 时发生未知错误: {e}")  # 错误打印
            return False

        finally:
            if conn:
                conn.close()

    # 新增方法：根据记录ID列表从数据库批量删除拉黑记录
    def batch_delete_blacklist_records_by_ids(self, record_ids):
        """
        根据数据库记录ID列表批量删除拉黑记录。
        参数: record_ids (list) - 要删除的拉黑记录ID列表
        返回: bool - 所有删除操作都成功返回 True，任一失败返回 False
                (或者可以返回成功删除的数量)
        """
        print(f"Api: 接收到批量删除拉黑记录请求，记录IDs: {record_ids}")  # 调试打印
        if not record_ids:
            print("Api: 批量删除请求 IDs 为空，未执行删除操作。")  # 调试打印
            return True  # 空列表视为成功处理

        conn = None
        success_count = 0
        try:
            root_path = os.getcwd()
            is_pack = getattr(sys, 'frozen', False)
            if is_pack:
                run_path = sys._MEIPASS
            else:
                run_path = root_path
            blacklist_records_path = os.path.join(run_path, 'blacklist_records.db')

            conn = sqlite3.connect(blacklist_records_path)
            c = conn.cursor()

            # 批量执行删除操作
            # 使用事务以提高效率和确保原子性
            conn.execute('BEGIN TRANSACTION;')
            for record_id in record_ids:
                try:
                    c.execute("DELETE FROM blacklist_records WHERE id = ?", (record_id,))
                    success_count += c.rowcount
                    print(f"Api: 尝试删除记录 (ID: {record_id})。影响行数: {c.rowcount}")  # 调试打印
                except sqlite3.Error as e:
                    print(f"Api: 数据库删除错误 (ID: {record_id}) 在批量操作中: {e}")  # 错误打印
                    # 可以在这里选择是否回滚整个事务或者记录失败并继续
                    # 为了简单，这里记录错误并继续
            conn.commit()
            print(f"Api: 批量删除操作完成。成功删除 {success_count} 条记录。")  # 调试打印

            # 如果使用后端缓存，批量删除后需要更新缓存
            # 这比较复杂，可能需要遍历删除的IDs找到涉及的 account_url_part 并刷新对应缓存

            return success_count == len(record_ids)  # 如果成功删除的数量等于请求的数量，返回 True

        except sqlite3.Error as e:
            print(f"Api: 数据库批量删除操作发生错误: {e}")  # 错误打印
            if conn:
                conn.rollback()  # 回滚事务
            return False  # 数据库错误返回 False

        except Exception as e:
            print(f"Api: 批量删除拉黑记录时发生未知错误: {e}")  # 错误打印
            return False

        finally:
            if conn:
                conn.close()

    # 新增方法：执行解除拉黑操作（调用 拉黑.py 中的 jclahei）
    def perform_unblock(self, account_url_part, user_sid):
        """
        调用 拉黑.py 中的 jclahei 方法执行解除拉黑操作。
        参数:
            account_url_part (str): 当前主播账号的 url_part
            user_sid (str): 要解除拉黑用户的 user_sid (抖音主页ID)
        返回: str - 解除拉黑操作的结果消息 (成功或失败原因)
        """
        print(
            f"Api: 接收到执行解除拉黑操作请求。账号 url_part: {account_url_part}, 用户 user_sid: {user_sid}")  # 调试打印

        cookie_file_path = f'./{account_url_part}.pkl'

        try:
            # 加载当前主播账号的 Cookie
            Cookie = load_cookies_from_file(cookie_file_path)
            if not Cookie:
                print(f"Api: perform_unblock: 未找到或加载 cookie 文件失败: {cookie_file_path}")  # 错误打印
                return "加载账号 Cookie 失败"

            # 调用 拉黑.py 中的 jclahei 方法
            # print(f"Api: 调用 jclahei 方法，参数：user_sid={user_sid}, Cookie={Cookie}")  # 调试打印
            # 注意：jclahei 方法中的 user_id 参数在您的 拉黑.py 中硬编码了一个值
            # jclahei(sec_user_id, Cookie, user_id='7454438944119719433')
            # 您需要修改 拉黑.py 中的 jclahei 方法，使其正确接收 user_id 参数，或者确认 user_id 是否必须以及如何获取。
            # 假设 user_sid 就是 jclahei 需要的 sec_user_id，并且 user_id 参数是可选或可以从 user_sid 推导。
            # 如果 jclahei 需要 user_id，您需要从数据库或其他地方获取它，或者修改数据库存储 user_id
            # 目前根据您的描述，jclahei 需要 user_sid 和 cookie。我们使用 user_sid 作为 sec_user_id 传入。
            # 关于 user_id 参数，根据 拉黑.py 代码，它有一个默认值 '7454438944119719433'。
            # 如果这个默认值不正确，或者需要传入实际被拉黑用户的 user_id，您需要调整这里的逻辑。
            # 检查 拉黑.py 中的 jclahei 实现，它似乎是 POST 到 /aweme/v1/web/user/block/，
            # payload 中包含 block_type=0（解除拉黑）、sec_user_id 和 user_id。
            # sec_user_id 应该是被拉黑用户的 user_sid，user_id 是被拉黑用户的数字ID。
            # 如果您的数据库中只存储了 user_sid，您可能需要修改 jclahei 或从数据库获取 user_id。
            # **重要：请仔细检查 拉黑.py 中 jclahei 方法需要的 user_id 参数是如何获取和使用的。**
            # **根据您的 `拉黑.py` 代码，jclahei 方法签名是 `jclahei(sec_user_id, Cookie, user_id='7454438944119719433')`**
            # **这里的 `user_id` 参数有一个硬编码的默认值。这可能不是您期望的。**
            # **您需要确保 `jclahei` 使用传入的 `sec_user_id` (即被拉黑用户的 user_sid) 来正确执行解除拉黑。**
            # **并且确认是否需要正确的 `user_id`，如果需要，您需要修改数据库存储 user_id，并在获取拉黑记录时一同返回。**
            # **以下代码假设 jclahei 可以仅通过 sec_user_id 和 Cookie 来解除拉黑。**

            # 临时代码：使用硬编码的 user_id 调用 jclahei，您需要根据实际情况修改
            # result = jclahei(user_sid, Cookie, user_id='7454438944119719433')

            # 更好的方法：如果数据库存储了 user_id (即前端的 item.userId)，获取它并传入
            # 这需要修改 get_blacklist_records 方法，让它也返回 user_id
            # 在 id-blacklist.html 中，我在创建列表项时已经将 item.userId 存储在 data-user-id 属性中
            # 前端调用时应该传入这个 user_id

            # 假设前端会传入 record_id 和 user_sid
            # 如果 jclahei 只需要 user_sid 和 Cookie，那么直接调用：
            result = jclahei(user_sid, Cookie)
            print(f"Api: jclahei 方法调用结果: {result}")  # 调试打印

            # 根据 jclahei 的返回值判断操作结果
            if result is True:
                print(f"Api: 解除拉黑成功，用户 user_sid: {user_sid}")  # 调试打印
                return "解除拉黑成功"
            else:
                print(f"Api: 解除拉黑失败或需要二次确认。结果: {result}")  # 调试打印
                # jclahei 可能返回错误信息或状态码，这里需要根据实际返回值处理
                if isinstance(result, str):
                    return f"解除拉黑失败: {result}"
                elif isinstance(result, int):
                    return f"解除拉黑失败: HTTP状态码 {result}"
                else:
                    return "解除拉黑失败: 未知错误"


        except FileNotFoundError:
            print(f"Api: perform_unblock: 未找到 cookie 文件: {cookie_file_path}")  # 错误打印
            return "加载账号 Cookie 失败"
        except Exception as e:
            print(f"Api: perform_unblock: 调用 jclahei 时发生错误: {e}")  # 错误打印
            return f"解除拉黑操作出错: {e}"

    # 新增方法：执行批量解除拉黑操作
    def perform_batch_unblock(self, account_url_part, user_sid_list):
            """
            批量调用 拉黑.py 中的 jclahei 方法执行解除拉黑操作。
            参数:
                account_url_part (str): 当前主播账号的 url_part
                user_sid_list (list): 要解除拉黑用户的 user_sid 列表
            返回: str - 批量解除拉黑操作的结果消息
            """
            print(
                f"Api: 接收到执行批量解除拉黑操作请求。账号 url_part: {account_url_part}, 用户 user_sid 列表: {user_sid_list}")  # 调试打印
            cookie_file_path = f'./{account_url_part}.pkl'
            results = {}  # 存储每个用户的解除结果

            try:
                # 加载当前主播账号的 Cookie
                Cookie = load_cookies_from_file(cookie_file_path)
                if not Cookie:
                    print(f"Api: perform_batch_unblock: 未找到或加载 cookie 文件失败: {cookie_file_path}")  # 错误打印
                    return json.dumps({"success": False, "message": "加载账号 Cookie 失败"})

                # 遍历用户列表，逐个调用 jclahei
                for user_sid in user_sid_list:
                    print(f"Api: 尝试解除拉黑用户 user_sid: {user_sid}")  # 调试打印
                    # 调用 拉黑.py 中的 jclahei 方法，同样需要注意 user_id 参数的问题
                    # 临时代码：使用硬编码的 user_id 调用 jclahei，您需要根据实际情况修改
                    # result = jclahei(user_sid, Cookie, user_id='7454438944119719433')
                    # 如果 jclahei 只需要 user_sid 和 Cookie，那么直接调用：
                    result = jclahei(user_sid, Cookie)

                    results[user_sid] = result  # 存储结果

                    # 可以添加一个短暂的延迟，避免请求过快
                    time.sleep(0.5)  # 例如延迟0.5秒

                print(f"Api: 批量解除拉黑操作完成。结果: {results}")  # 调试打印

                # 统计成功和失败数量，构建返回消息
                success_count = sum(1 for r in results.values() if r is True)
                failed_users = [uid for uid, r in results.items() if r is not True]

                if not failed_users:
                    message = f"成功解除拉黑 {success_count} 个用户。"
                    return json.dumps({"success": True, "message": message})
                else:
                    message = f"成功解除拉黑 {success_count} 个用户，{len(failed_users)} 个用户失败。"
                    # 可以在消息中包含失败用户的 user_sid 或错误详情，但这可能暴露过多信息，按需调整
                    return json.dumps({"success": False, "message": message, "failed_users": failed_users})


            except FileNotFoundError:
                print(f"Api: perform_batch_unblock: 未找到 cookie 文件: {cookie_file_path}")  # 错误打印
                return json.dumps({"success": False, "message": "加载账号 Cookie 失败"})
            except Exception as e:
                print(f"Api: perform_batch_unblock: 调用 jclahei 时发生错误: {e}")  # 错误打印
                return json.dumps({"success": False, "message": f"批量解除拉黑操作出错: {e}"})

if __name__ == '__main__':

    root_path = os.getcwd()
    is_pack = getattr(sys, 'frozen', False)
    if is_pack:
        run_path = sys._MEIPASS
    else:
        run_path = root_path
    json_path = os.path.join(run_path, 'index', 'user_Settings_Options.json')

    if not os.path.exists(json_path):
        with open(json_path, 'w', encoding='utf-8') as f:
            f.write(
                '{"id-whitelist":{"name":"id白名单","enabled":false,"option":"","inputValue":""},"id-blacklist-rule":{"name":"id黑名单","enabled":false,"inputValue":""},"danmaku":{"name":"弹幕关键词拉黑","enabled":false,"inputValue":""},"local-data":{"name":"数据互通","enabled":false},"suspected-account":{"name":"疑似账号","enabled":false},"follow":{"name":"关注拉黑","enabled":false},"share-entry":{"name":"通过分享进入直播间","enabled":false},"follow-entry":{"name":"通过关注进入直播间","enabled":false},"private-account":{"name":"私密账号","enabled":false},"blue-v":{"name":"开通蓝v","enabled":false},"share":{"name":"分享拉黑","enabled":false,"options":[]},"gender":{"name":"性别拉黑","enabled":false,"options":[]},"age-range":{"name":"年龄区间拉黑","enabled":false,"inputValue":""},"follower-count":{"name":"粉丝数量大于拉黑","enabled":false,"inputValue":""},"following-count":{"name":"关注数量大于拉黑","enabled":false,"inputValue":""},"work-count":{"name":"作品数量大于拉黑","enabled":false,"inputValue":""},"entry-count":{"name":"用户进入次数拉黑","enabled":false,"inputValue":""},"nickname":{"name":"昵称关键词","enabled":false,"inputValue":""},"signature":{"name":"个性签名关键词拉黑","enabled":false,"inputValue":""},"region":{"name":"地区拉黑","enabled":false,"inputValue":""},"ip":{"name":"IP拉黑","enabled":false,"inputValue":""}}')
    blacklist_records_path = os.path.join(run_path, 'blacklist_records.db')
    # 创建数据库 如果存在则不创建
    if not os.path.exists(blacklist_records_path):
        conn = sqlite3.connect(blacklist_records_path)
        c = conn.cursor()
        # 创建表
        c.execute('''CREATE TABLE blacklist_records
                     (
                         id               INTEGER PRIMARY KEY AUTOINCREMENT, -- 自增主键
                         account_url_part TEXT NOT NULL,                     -- 拉黑该记录的主播账号的 url_part (sec_uid)
                         user_sid         TEXT NOT NULL,                     -- 被拉黑用户的抖音主页ID (user_sid)
                         user_douyin_id   TEXT,                              -- 被拉黑用户的抖音号 (display_id)
                         user_nickname    TEXT,                              -- 被拉黑用户的昵称
                         user_avatar      TEXT,                              -- 被拉黑用户的头像URL
                         blacklist_reason TEXT,                              -- 拉黑原因
                         blacklist_time   TEXT,                              -- 拉黑时间 (YYYY-MM-DD HH:MM:SS 格式文本)
                         -- 联合唯一约束：同一个主播账号不能重复拉黑同一个用户 (通过 user_sec_uid 判断)
                         UNIQUE (account_url_part, user_sid)

                     )''')
        conn.commit()
        conn.close()

    api = Api()

    window_html = os.path.join(run_path, 'index', 'live-management.html')
    # 在 create_window 中设置 api 对象，以便 JS 访问
    window = webview.create_window('直播管理系统', window_html, js_api=api, min_size=(800, 600))

    # 启动 webview。启动后，界面将显示。
    # live-management.html 中的 JS 代码应在 DOM 准备就绪且 pywebview api 可用后调用 get_initial_accounts()
    webview.start(debug=True)
