import re
import time
from datetime import datetime, timedelta
from http.cookies import SimpleCookie

import pytz
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from cloakbrowser import launch_context

from app.core.config import settings
from app.plugins import _PluginBase
from typing import Any, List, Dict, Tuple, Optional
from app.log import logger
from app.schemas import NotificationType
from app.utils.http import RequestUtils


class InvitesSignin(_PluginBase):
    # 插件名称
    plugin_name = "药丸签到"
    # 插件描述
    plugin_desc = "药丸论坛签到。"
    # 插件图标
    plugin_icon = "invites.png"
    # 插件版本
    plugin_version = "3.0.0"
    # 插件作者
    plugin_author = "thsrite"
    # 作者主页
    author_url = "https://github.com/thsrite"
    # 插件配置项ID前缀
    plugin_config_prefix = "invitessignin_"
    # 加载顺序
    plugin_order = 24
    # 可使用的用户级别
    auth_level = 2

    # 私有属性
    _enabled = False
    # 任务执行间隔
    _cron = None
    _cookie = None
    _onlyonce = False
    _notify = False
    # 代理 / 浏览器仿真
    _use_proxy = True  # 是否使用代理，默认启用
    _use_browser_emulation = False  # 是否启用浏览器仿真（绕过CF防护）
    _history_days = None
    _username = None
    _user_password = None
    _retry_count = 2
    _retry_interval = 5
    # User-Agent 字符串常量
    _user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"

    # 定时器
    _scheduler: Optional[BackgroundScheduler] = None
    def init_plugin(self, config: dict = None):
        # 停止现有任务
        self.stop_service()

        if config:
            self._enabled = config.get("enabled")
            self._cron = config.get("cron")
            self._cookie = config.get("cookie")
            self._notify = config.get("notify")
            self._onlyonce = config.get("onlyonce")
            self._use_proxy = config.get("use_proxy", True)
            self._use_browser_emulation = config.get("use_browser_emulation", False)
            self._history_days = int(config.get("history_days") or 30)
            self._username = config.get("username")
            self._user_password = config.get("user_password")
            self._retry_count = int(config.get("retry_count") or 2)
            self._retry_interval = int(config.get("retry_interval") or 5)

        if self._onlyonce:
            # 定时服务
            self._scheduler = BackgroundScheduler(timezone=settings.TZ)
            logger.info(f"药丸签到服务启动，立即运行一次")
            self._scheduler.add_job(func=self.__signin, trigger='date',
                                    run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
                                    name="药丸签到")
            # 关闭一次性开关
            self._onlyonce = False
            self.update_config({
                "onlyonce": False,
                "cron": self._cron,
                "enabled": self._enabled,
                "cookie": self._cookie,
                "notify": self._notify,
                "use_proxy": self._use_proxy,
                "use_browser_emulation": self._use_browser_emulation,
                "history_days": self._history_days,
                "username": self._username,
                "user_password": self._user_password,
                "retry_count": self._retry_count,
                "retry_interval": self._retry_interval
            })

            # 启动任务
            if self._scheduler.get_jobs():
                self._scheduler.print_jobs()
                self._scheduler.start()

    def _get_page_source(self, url: str, cookies=None) -> Optional[str]:
        """
        获取页面HTML源码。
        若启用浏览器仿真，使用 CloakBrowser 获取页面；否则走普通HTTP请求。
        """
        proxies = self.__get_proxies()
        proxy_server = settings.PROXY_SERVER if self._use_proxy else None

        if self._use_browser_emulation:
            logger.info(f"[浏览器仿真] 使用 CloakBrowser 请求: {url}")
            return self.__get_page_source_with_cloakbrowser(url=url, cookies=cookies, proxy=proxy_server)

        res = RequestUtils(cookies=cookies, proxies=proxies).get_res(url=url)
        if res and res.status_code == 200:
            return res.text
        logger.error(f"普通请求失败: {url}, 状态码: {res.status_code if res else '无响应'}")
        return None

    @staticmethod
    def __get_page_source_with_cloakbrowser(url: str, cookies: Optional[str] = None,
                                            proxy: Optional[dict] = None) -> Optional[str]:
        """
        使用 CloakBrowser 渲染页面，适配启用浏览器仿真的站点请求。
        """
        context = None
        page = None
        try:
            context = launch_context(headless=True, proxy=proxy)
            page = context.new_page()
            if cookies:
                page.set_extra_http_headers({"cookie": cookies})
            page.goto(url)
            page.wait_for_load_state("networkidle", timeout=60 * 1000)
            return page.content()
        except Exception as e:
            logger.error(f"CloakBrowser 请求失败: {url}, 错误: {e}")
            return None
        finally:
            if page:
                page.close()
            if context:
                context.close()

    def __get_proxies(self):
        """
        获取代理设置
        """
        if not self._use_proxy:
            logger.debug("未启用代理")
            return None

        try:
            # 获取系统代理设置
            if hasattr(settings, 'PROXY') and settings.PROXY:
                logger.debug(f"使用系统代理: {settings.PROXY}")
                return settings.PROXY
            else:
                logger.debug("系统代理未配置")
                return None
        except Exception as e:
            logger.error(f"获取代理设置出错: {str(e)}")
            return None

    def __get_new_session(self, flarum_remember: str) -> str:
        """获取新的session"""
        headers = {
            "Cookie": f"flarum_remember={flarum_remember}",
            "User-Agent": self._user_agent,
            "Upgrade-Insecure-Requests": "1",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
        }
        
        # 获取代理
        proxies = self.__get_proxies()
        
        # 尝试获取新session，禁止重定向以便捕获Set-Cookie
        response = RequestUtils(headers=headers, proxies=proxies).get_res(url="https://invites.fun", allow_redirects=False)
        if not response:
            return None
            
        # 1. 优先尝试从 response.cookies 中获取 (requests 自动处理)
        if response.cookies.get('flarum_session'):
            return response.cookies.get('flarum_session')

        # 2. 作为备用，尝试从 Set-Cookie 响应头中提取
        cookies = response.headers.get('Set-Cookie', '')
        session_match = re.search(r'flarum_session=([^;]+)', cookies)
        if session_match:
            return session_match.group(1)
            
        return None

    def __get_remember_value(self, cookie: str) -> str:
        """从cookie字符串中提取flarum_remember值"""
        remember_match = re.search(r'flarum_remember=([^;]+)', cookie)
        if remember_match:
            return remember_match.group(1)
        return None

    def __parse_cookie_string(self, cookie_str: str) -> dict:
        """安全地解析cookie字符串，返回cookie字典"""
        try:
            # 使用SimpleCookie解析cookie字符串
            cookie = SimpleCookie()
            cookie.load(cookie_str)
            
            # 提取需要的cookie值
            cookies = {}
            if 'flarum_remember' in cookie:
                cookies['flarum_remember'] = cookie['flarum_remember'].value
            if 'flarum_session' in cookie:
                cookies['flarum_session'] = cookie['flarum_session'].value
                
            return cookies
        except Exception as e:
            logger.error(f"解析cookie字符串失败: {e}")
            # 如果解析失败，返回空字典
            return {}

    def __login_with_credentials(self) -> dict:
        """使用用户名和密码登录药丸"""
        try:
            # 第一步：获取初始session和csrf token
            headers_get = {
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
                'Accept-Language': 'zh-CN,zh;q=0.9',
                'User-Agent': self._user_agent,
                'Upgrade-Insecure-Requests': '1'
            }
            
            # 获取代理
            proxies = self.__get_proxies()
            
            response_get = RequestUtils(headers=headers_get, proxies=proxies).get_res('https://invites.fun/')
            if not response_get or response_get.status_code != 200:
                logger.error("获取初始session失败")
                return {"success": False, "error": "获取初始session失败"}
            
            # 从响应中提取flarum_session和csrf token
            flarum_session = response_get.cookies.get('flarum_session')
            csrf_token = response_get.headers.get('x-csrf-token')
            
            if not flarum_session:
                logger.error("未获取到flarum_session")
                return {"success": False, "error": "未获取到flarum_session"}
            
            if not csrf_token:
                logger.error("未获取到csrf token")
                return {"success": False, "error": "未获取到csrf token"}
            
            logger.info(f"获取到初始session: {flarum_session}")
            logger.info(f"获取到csrf token: {csrf_token}")
            
            # 第二步：执行登录
            cookies_login = {
                'flarum_session': flarum_session,
            }
            
            headers_login = {
                'Accept': '*/*',
                'Content-Type': 'application/json; charset=UTF-8',
                'Origin': 'https://invites.fun',
                'Referer': 'https://invites.fun/',
                'x-csrf-token': csrf_token,
                'User-Agent': self._user_agent
            }
            
            json_data_login = {
                'identification': self._username,
                'password': self._user_password,
                'remember': True,
            }
            
            login_response = RequestUtils(cookies=cookies_login, headers=headers_login, proxies=proxies).post_res(
                'https://invites.fun/login', 
                json=json_data_login
            )
            
            if not login_response or login_response.status_code != 200:
                logger.error(f"登录失败，状态码: {login_response.status_code if login_response else 'None'}")
                return {"success": False, "error": "登录失败"}
            
            # 从登录响应中提取新的cookies和用户信息
            flarum_remember = login_response.cookies.get('flarum_remember')
            flarum_session_new = login_response.cookies.get('flarum_session')
            csrf_token_new = login_response.headers.get('X-CSRF-Token') or csrf_token
            
            if not flarum_remember or not flarum_session_new:
                logger.error("登录后未获取到有效的cookies")
                return {"success": False, "error": "登录后未获取到有效的cookies"}
            
            # 提取用户ID
            user_id = None
            try:
                login_data = login_response.json()
                user_id = login_data.get('userId')
            except Exception as e:
                logger.error(f"解析登录响应失败: {e}")
                return {"success": False, "error": "解析登录响应失败"}
            
            if not user_id:
                logger.error("未获取到用户ID")
                return {"success": False, "error": "未获取到用户ID"}
            
            logger.info(f"登录成功，用户ID: {user_id}")
            
            return {
                "success": True,
                "flarum_remember": flarum_remember,
                "flarum_session": flarum_session_new,
                "csrf_token": csrf_token_new,
                "user_id": user_id
            }
            
        except Exception as e:
            logger.error(f"登录过程中发生异常: {e}")
            return {"success": False, "error": f"登录异常: {e}"}

    def __update_cookie_if_changed(self, new_cookie_str: str):
        """
        检查Cookie是否发生变化，如果有变化则更新配置
        """
        try:
            if not new_cookie_str:
                return

            # 解析新Cookie
            new_cookies = self.__parse_cookie_string(new_cookie_str)
            new_remember = new_cookies.get('flarum_remember')
            new_session = new_cookies.get('flarum_session')

            if not new_remember or not new_session:
                return

            # 解析旧Cookie
            old_cookies = self.__parse_cookie_string(self._cookie or "")
            old_remember = old_cookies.get('flarum_remember')
            old_session = old_cookies.get('flarum_session')

            # 对比是否变化
            if new_remember != old_remember or new_session != old_session:
                # 构造标准格式的Cookie字符串
                final_cookie = f"flarum_remember={new_remember}; flarum_session={new_session}"
                
                logger.info(f"Cookie已更新，保存新配置")
                
                # 更新内存中的配置
                self._cookie = final_cookie
                
                # 更新持久化配置
                self.update_config({
                    "onlyonce": self._onlyonce,
                    "cron": self._cron,
                    "enabled": self._enabled,
                    "cookie": self._cookie,
                    "notify": self._notify,
                    "use_proxy": self._use_proxy,
                    "use_browser_emulation": self._use_browser_emulation,
                    "history_days": self._history_days,
                    "username": self._username,
                    "user_password": self._user_password,
                    "retry_count": self._retry_count,
                    "retry_interval": self._retry_interval
                })
            else:
                logger.debug("Cookie未发生变化，无需更新")
                
        except Exception as e:
            logger.error(f"更新Cookie配置失败: {e}")

    def __signin(self):
        """药丸签到"""
        # 1. 检查今日是否已签到
        try:
            history = self.get_data('history') or []
            if history:
                # 按时间倒序排序
                history = sorted(history, key=lambda x: x.get("date") or "", reverse=True)
                last_checkin = history[0]
                last_date = last_checkin.get("date", "")
                if last_date:
                    # 获取今日日期字符串 YYYY-MM-DD
                    today_str = datetime.now().strftime('%Y-%m-%d')
                    if last_date.startswith(today_str):
                        logger.info(f"今日已签到 ({last_date})，跳过本次任务")
                        return
        except Exception as e:
            logger.warning(f"检查签到历史失败: {e}")

        for attempt in range(self._retry_count):
            logger.info(f"开始第 {attempt + 1} 次签到尝试")
            
            # 尝试使用cookie签到
            cookie_success = self.__signin_with_cookie()
            if cookie_success:
                logger.info(f"第 {attempt + 1} 次签到成功（Cookie方式）")
                return
            
            # Cookie签到失败，尝试使用用户名密码登录签到
            logger.info(f"第 {attempt + 1} 次Cookie签到失败，尝试用户名密码登录签到")
            login_success = self.__signin_with_login()
            if login_success:
                logger.info(f"第 {attempt + 1} 次签到成功（登录方式）")
                return
            
            # 两种方式都失败
            logger.warning(f"第 {attempt + 1} 次签到失败")
            
            # 如果不是最后一次尝试，等待重试间隔
            if attempt < self._retry_count - 1:
                logger.info(f"等待 {self._retry_interval} 分钟后进行第 {attempt + 2} 次重试")
                time.sleep(self._retry_interval * 60)  # 转换为秒
        
        # 所有重试都失败
        logger.error(f"所有 {self._retry_count} 次签到尝试都失败了")
        
        # 发送签到失败通知
        if self._notify:
            self.post_message(
                mtype=NotificationType.SiteMessage,
                title='【💊药丸签到】任务完成',
                text='━━━━━━━━━━━━━━\n'
                     '✨ 状态：❌签到失败\n'
                     '━━━━━━━━━━━━━━\n'
                     f'❗ 原因：已重试{self._retry_count}次，Cookie失效且账号密码登录失败\n'
                     '━━━━━━━━━━━━━━\n'
                     f'🕐 时间：{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')

    def __signin_with_cookie(self) -> bool:
        """使用Cookie进行签到"""
        try:
            # 检查cookie是否配置
            if not self._cookie or not self._cookie.strip():
                logger.info("Cookie未配置，跳过Cookie签到")
                return False
            
            # 1. 从配置的cookie中提取flarum_remember值
            flarum_remember = self.__get_remember_value(self._cookie)
            if not flarum_remember:
                logger.error("无法从cookie中提取flarum_remember值")
                return False

            # 2. 使用flarum_remember获取新的session
            new_session = self.__get_new_session(flarum_remember)
            if not new_session:
                logger.error("获取新session失败")
                return False
                
            # 3. 构建新的cookie
            new_cookie = f"flarum_remember={flarum_remember}; flarum_session={new_session}"
            logger.info("成功刷新session")
            
            # 获取代理
            proxies = self.__get_proxies()
            
            # 4. 使用新cookie获取csrfToken和userId
            page_html = self._get_page_source("https://invites.fun", cookies=new_cookie)
            if not page_html:
                logger.error("请求药丸错误")
                return False

            # 获取csrfToken
            pattern = r'"csrfToken":"(.*?)"'
            csrfToken = re.findall(pattern, page_html)
            if not csrfToken:
                logger.error("请求csrfToken失败")
                return False

            csrfToken = csrfToken[0]
            logger.info(f"获取csrfToken成功 {csrfToken}")

            # 获取userid
            pattern = r'"userId":(\d+)'
            match = re.search(pattern, page_html)

            if match:
                userId = match.group(1)
                logger.info(f"获取userid成功 {userId}")
            else:
                logger.error("未找到userId")
                return False
                
            # 执行签到
            result = self.__perform_checkin(userId, new_cookie, csrfToken)
            
            # 如果签到成功，尝试更新Cookie
            if result:
                self.__update_cookie_if_changed(new_cookie)
                
            return result
            
        except Exception as e:
            logger.error(f"Cookie签到过程中发生异常: {e}")
            return False

    def __signin_with_login(self) -> bool:
        """使用用户名密码登录进行签到"""
        try:
            # 检查用户名和密码是否配置
            if not self._username or not self._user_password:
                logger.error("用户名或密码未配置，无法使用登录签到")
                return False
            
            # 执行登录
            login_result = self.__login_with_credentials()
            if not login_result.get("success"):
                logger.error(f"登录失败: {login_result.get('error', '未知错误')}")
                return False
            
            # 构建cookie字符串
            cookie_str = f"flarum_remember={login_result['flarum_remember']}; flarum_session={login_result['flarum_session']}"
            
            # 执行签到
            result = self.__perform_checkin(
                login_result['user_id'], 
                cookie_str, 
                login_result['csrf_token']
            )
            
            # 如果签到成功，尝试更新Cookie
            if result:
                self.__update_cookie_if_changed(cookie_str)
                
            return result
            
        except Exception as e:
            logger.error(f"登录签到过程中发生异常: {e}")
            return False

    def __perform_checkin(self, user_id: str, cookie_str: str, csrf_token: str) -> bool:
        """执行实际的签到操作"""
        try:
            # 构建签到请求的headers
            headers = {
                'accept': '*/*',
                'content-type': 'application/json; charset=UTF-8',
                'origin': 'https://invites.fun',
                'referer': 'https://invites.fun/',
                'x-csrf-token': csrf_token,
                'x-http-method-override': 'PATCH',
                'user-agent': self._user_agent
            }
            
            # 构建签到请求的JSON数据
            json_data = {
                'data': {
                    'type': 'users',
                    'attributes': {
                        'canCheckin': False,
                        'totalContinuousCheckIn': 2, #连续签到天数
                    },
                    'id': str(user_id),
                },
            }
            
            # 构建cookies - 使用安全的解析方法
            cookies = self.__parse_cookie_string(cookie_str)
            
            # 验证必要的cookie是否存在
            if not cookies.get('flarum_remember') or not cookies.get('flarum_session'):
                logger.error("cookie中缺少必要的flarum_remember或flarum_session值")
                return False
            
            # 获取代理
            proxies = self.__get_proxies()
            
            # 执行签到请求
            checkin_url = f'https://invites.fun/api/users/{user_id}'
            response = RequestUtils(cookies=cookies, headers=headers, proxies=proxies).post_res(
                checkin_url, 
                json=json_data
            )
            
            if not response or response.status_code != 200:
                logger.error(f"签到请求失败，状态码: {response.status_code if response else 'None'}")
                return False
            
            # 解析签到响应
            try:
                checkin_data = response.json()
                
                # 提取关键信息
                total_continuous_checkin = checkin_data['data']['attributes']['totalContinuousCheckIn']
                money = checkin_data['data']['attributes']['money']
                
                logger.info("药丸签到成功")
                
                # 发送通知
                if self._notify:
                    self.post_message(
                        mtype=NotificationType.SiteMessage,
                        title="【💊药丸签到】任务完成",
                        text="━━━━━━━━━━━━━━\n"
                             "✨ 状态：✅已签到\n"
                             "━━━━━━━━━━━━━━\n"
                             "📊 数据统计\n"
                             f"💊 剩余药丸：{money}\n"
                             f"📆 累计签到：{total_continuous_checkin}天\n"
                             "━━━━━━━━━━━━━━\n"
                             f"🕐 签到时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                
                # 保存签到历史
                history = self.get_data('history') or []
                history.append({
                    "date": datetime.today().strftime('%Y-%m-%d %H:%M:%S'),
                    "totalContinuousCheckIn": total_continuous_checkin,
                    "money": money
                })
                
                # 清理超过保留天数的历史记录
                thirty_days_ago = time.time() - int(self._history_days) * 24 * 60 * 60
                history = [record for record in history if
                           datetime.strptime(record["date"], '%Y-%m-%d %H:%M:%S').timestamp() >= thirty_days_ago]
                
                # 保存签到历史
                self.save_data(key="history", value=history)
                
                return True
                
            except Exception as e:
                logger.error(f"解析签到响应失败: {e}")
                logger.error(f"签到响应内容: {response.text if response else 'None'}")
                return False
                
        except Exception as e:
            logger.error(f"执行签到过程中发生异常: {e}")
            return False

    def get_state(self) -> bool:
        return self._enabled

    @staticmethod
    def get_command() -> List[Dict[str, Any]]:
        pass

    def get_api(self) -> List[Dict[str, Any]]:
        pass

    def get_service(self) -> List[Dict[str, Any]]:
        """
        注册插件公共服务
        [{
            "id": "服务ID",
            "name": "服务名称",
            "trigger": "触发器：cron/interval/date/CronTrigger.from_crontab()",
            "func": self.xxx,
            "kwargs": {} # 定时器参数
        }]
        """
        if self._enabled and self._cron:
            return [{
                "id": "InvitesSignin",
                "name": "药丸签到服务",
                "trigger": CronTrigger.from_crontab(self._cron),
                "func": self.__signin,
                "kwargs": {}
            }]
        return []

    def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
        """
        拼装插件配置页面，需要返回两块数据：1、页面配置；2、数据结构
        """
        version = getattr(settings, "VERSION_FLAG", "v1")
        cron_field_component = "VCronField" if version == "v2" else "VTextField"
        return [
            {
                'component': 'VForm',
                'content': [
                    # 基础设置卡片
                    {
                        'component': 'VCard',
                        'props': {'class': 'mt-0'},
                        'content': [
                            {'component': 'VCardTitle', 'props': {'class': 'd-flex align-center'}, 'content': [
                                {'component': 'VIcon', 'props': {'color': 'info', 'class': 'mr-2'}, 'text': 'mdi-cog'},
                                {'component': 'span', 'text': '基础设置'}
                            ]},
                            {'component': 'VDivider'},
                            {'component': 'VCardText', 'content': [
                                {'component': 'VRow', 'content': [
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [{'component': 'VSwitch', 'props': {'model': 'enabled', 'label': '启用插件', 'color': 'primary'}}]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [{'component': 'VSwitch', 'props': {'model': 'use_proxy', 'label': '使用代理', 'color': 'warning'}}]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [{'component': 'VSwitch', 'props': {'model': 'notify', 'label': '开启通知', 'color': 'info'}}]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [{'component': 'VSwitch', 'props': {'model': 'onlyonce', 'label': '立即运行一次', 'color': 'success'}}]},
                                ]},
                                {'component': 'VRow', 'content': [
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [{'component': 'VSwitch', 'props': {'model': 'use_browser_emulation', 'label': '启用浏览器仿真', 'color': '#009688'}}]},
                                ]},
                            ]}
                        ]
                    },
                    # 登录设置卡片
                    {
                        'component': 'VCard',
                        'props': {'class': 'mt-3'},
                        'content': [
                            {'component': 'VCardTitle', 'props': {'class': 'd-flex align-center'}, 'content': [
                                {'component': 'VIcon', 'props': {'color': 'info', 'class': 'mr-2'}, 'text': 'mdi-pill'},
                                {'component': 'span', 'text': '账号设置'}
                            ]},
                            {'component': 'VDivider'},
                            {'component': 'VCardText', 'content': [
                                {'component': 'VRow', 'content': [
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'username',
                                            'label': '用户名',
                                            'placeholder': '请输入用户名',
                                            'prepend-inner-icon': 'mdi-account',
                                            'autocomplete': 'new-username',
                                            'persistent-placeholder': True,
                                            'clearable': True
                                        }}
                                    ]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'user_password',
                                            'label': '密码',
                                            'placeholder': '请输入密码',
                                            'prepend-inner-icon': 'mdi-lock',
                                            'type': 'password',
                                            'autocomplete': 'new-password',
                                            'persistent-placeholder': True,
                                            'clearable': True
                                        }}
                                    ]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': cron_field_component, 'props': {
                                            'model': 'cron',
                                            'label': '签到周期',
                                            'placeholder': '0 9 * * *',
                                            'prepend-inner-icon': 'mdi-clock-outline'
                                        }}
                                    ]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'history_days',
                                            'label': '历史记录保留天数',
                                            'type': 'number',
                                            'placeholder': '默认保留30天',
                                            'prepend-inner-icon': 'mdi-calendar-range'
                                        }}
                                    ]}
                                ]},
                                {'component': 'VRow', 'content': [
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 6}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'cookie',
                                            'label': 'Cookie',
                                            'placeholder': '需要包含 flarum_remember 值',
                                            'prepend-inner-icon': 'mdi-cookie',
                                            'type': 'password',
                                            'autocomplete': 'new-cookie',
                                            'persistent-placeholder': True,
                                            'clearable': True
                                        }}
                                    ]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'retry_count',
                                            'label': '失败重试次数',
                                            'placeholder': '默认2次',
                                            'prepend-inner-icon': 'mdi-refresh',
                                            'type': 'number',
                                            'persistent-placeholder': True,
                                            'clearable': True
                                        }}
                                    ]},
                                    {'component': 'VCol', 'props': {'cols': 12, 'md': 3}, 'content': [
                                        {'component': 'VTextField', 'props': {
                                            'model': 'retry_interval',
                                            'label': '失败重试间隔(分钟)',
                                            'placeholder': '默认5分钟',
                                            'prepend-inner-icon': 'mdi-timer-outline',
                                            'type': 'number',
                                            'persistent-placeholder': True,
                                            'clearable': True
                                        }}
                                    ]}
                                ]}
                            ]}
                        ]
                    },
                    # 使用说明卡片
                    {
                        'component': 'VCard',
                        'props': {'class': 'mt-3'},
                        'content': [
                            {'component': 'VCardTitle', 'props': {'class': 'd-flex align-center'}, 'content': [
                                {'component': 'VIcon', 'props': {'color': 'info', 'class': 'mr-2'}, 'text': 'mdi-information'},
                                {'component': 'span', 'text': '使用说明'}
                            ]},
                            {'component': 'VDivider'},
                            {'component': 'VCardText', 'props': {'class': 'px-6 pb-6'}, 'content': [
                                {
                                    'component': 'VList',
                                    'props': {'lines': 'two', 'density': 'comfortable'},
                                    'content': [
                                        {
                                            'component': 'VListItem',
                                            'props': {'lines': 'two'},
                                            'content': [
                                                {'component': 'div', 'props': {'class': 'd-flex align-items-start'}, 'content': [
                                                    {'component': 'VIcon', 'props': {'color': 'primary', 'class': 'mt-1 mr-2'}, 'text': 'mdi-calendar-clock'},
                                                    {'component': 'div', 'props': {'class': 'text-subtitle-1 font-weight-regular mb-1', 'style': 'color: #444;'}, 'text': '签到周期说明'}
                                                ]},
                                                {'component': 'div', 'props': {'class': 'text-body-2 ml-8'}, 'text': '支持标准cron表达式，建议错开整点，避免服务器高峰。默认09:00签到。'}
                                            ]
                                        },
                                        {
                                            'component': 'VListItem',
                                            'props': {'lines': 'two'},
                                            'content': [
                                                {'component': 'div', 'props': {'class': 'd-flex align-items-start'}, 'content': [
                                                    {'component': 'VIcon', 'props': {'color': 'warning', 'class': 'mt-1 mr-2'}, 'text': 'mdi-cookie'},
                                                    {'component': 'div', 'props': {'class': 'text-subtitle-1 font-weight-regular mb-1', 'style': 'color: #444;'}, 'text': 'Cookie说明'}
                                                ]},
                                                {'component': 'div', 'props': {'class': 'text-body-2 ml-8'}, 'text': '需要包含flarum_remember值，登录获取ck：https://invites.fun，登录时勾选记住我的登录状态。'}
                                            ]
                                        },
                                        {
                                            'component': 'VListItem',
                                            'props': {'lines': 'two'},
                                            'content': [
                                                {'component': 'div', 'props': {'class': 'd-flex align-items-start'}, 'content': [
                                                    {'component': 'VIcon', 'props': {'color': 'success', 'class': 'mt-1 mr-2'}, 'text': 'mdi-check-circle'},
                                                    {'component': 'div', 'props': {'class': 'text-subtitle-1 font-weight-regular mb-1', 'style': 'color: #444;'}, 'text': '功能特点'}
                                                ]},
                                                 {'component': 'div', 'props': {'class': 'text-body-2 ml-8'}, 'text': '优先使用填写Cookie进行签到，自动刷新session，如果Cookie签到失败或未设置则尝试进行登陆签到，支持签到历史记录查看。'}
                                             ]
                                         },
                                         {
                                             'component': 'VListItem',
                                             'props': {'lines': 'two'},
                                             'content': [
                                                 {'component': 'div', 'props': {'class': 'd-flex align-items-start'}, 'content': [
                                                     {'component': 'VIcon', 'props': {'color': '#009688', 'class': 'mt-1 mr-2'}, 'text': 'mdi-robot'},
                                                     {'component': 'div', 'props': {'class': 'text-subtitle-1 font-weight-regular mb-1', 'style': 'color: #444;'}, 'text': '浏览器仿真说明'}
                                                 ]},
                                                 {'component': 'div', 'props': {'class': 'text-body-2 ml-8'}, 'text': '开启后将使用 CloakBrowser 获取页面，可绕过 Cloudflare 防护。浏览器运行环境须在 MoviePilot 中提前准备。'}
                                            ]
                                        }
                                    ]
                                }
                            ]}
                        ]
                    }
                ]
            }
        ], {
            "enabled": False,
            "onlyonce": False,
            "notify": False,
            "use_proxy": True,
            "use_browser_emulation": False,
            "cookie": "",
            "history_days": 30,
            "cron": "0 9 * * *",
            "username": "",
            "user_password": "",
            "retry_count": 2,
            "retry_interval": 5
        }

    def get_page(self) -> List[dict]:
        # 查询同步详情
        historys = self.get_data('history')
        if not historys:
            return [
                {
                    'component': 'VCard',
                    'props': {
                        'variant': 'flat',
                        'class': 'mb-4'
                    },
                    'content': [
                        {
                            'component': 'VCardItem',
                            'props': {
                                'class': 'pa-6'
                            },
                            'content': [
                                {
                                    'component': 'VCardTitle',
                                    'props': {
                                        'class': 'd-flex align-center text-h6'
                                    },
                                    'content': [
                                        {
                                            'component': 'VIcon',
                                            'props': {
                                                'color': 'primary',
                                                'class': 'mr-3',
                                                'size': 'default'
                                            },
                                            'text': 'mdi-database-remove'
                                        },
                                        {
                                            'component': 'span',
                                            'text': '暂无签到记录'
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]

        if not isinstance(historys, list):
            historys = [historys]

        # 按照签到时间倒序
        historys = sorted(historys, key=lambda x: x.get("date") or 0, reverse=True)

        # 取前N条记录
        max_count = self._history_days or 30
        historys = historys[:max_count]

        return [
            {
                'component': 'VCard',
                'props': {
                    'variant': 'flat',
                    'class': 'mb-4 elevation-2',
                    'style': 'border-radius: 16px;'
                },
                'content': [
                    {
                        'component': 'VCardItem',
                        'props': {
                            'class': 'pa-6'
                        },
                        'content': [
                            {
                                'component': 'VCardTitle',
                                'props': {
                                    'class': 'd-flex align-center text-h6'
                                },
                                'content': [
                                    {
                                        'component': 'VIcon',
                                        'props': {
                                            'color': 'primary',
                                            'class': 'mr-3',
                                            'size': 'default'
                                        },
                                        'text': 'mdi-history'
                                    },
                                    {
                                        'component': 'span',
                                        'text': '签到历史记录'
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        'component': 'VCardText',
                        'props': {
                            'class': 'pa-6'
                        },
                        'content': [
                            {
                                'component': 'VTable',
                                'props': {
                                    'hover': True,
                                    'density': 'comfortable',
                                    'class': 'rounded-lg'
                                },
                                'content': [
                                    {
                                        'component': 'thead',
                                        'content': [
                                            {
                                                'component': 'tr',
                                                'content': [
                                                    {
                                                        'component': 'th',
                                                        'props': {
                                                            'class': 'text-center text-body-1 font-weight-bold'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'info', 'size': 'small', 'class': 'mr-1'}, 'text': 'mdi-clock-time-four-outline'},
                                                            {'component': 'span', 'text': '签到时间'}
                                                        ]
                                                    },
                                                    {
                                                        'component': 'th',
                                                        'props': {
                                                            'class': 'text-center text-body-1 font-weight-bold'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'success', 'size': 'small', 'class': 'mr-1'}, 'text': 'mdi-check-circle'},
                                                            {'component': 'span', 'text': '签到状态'}
                                                        ]
                                                    },
                                                    {
                                                        'component': 'th',
                                                        'props': {
                                                            'class': 'text-center text-body-1 font-weight-bold'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'info', 'size': 'small', 'class': 'mr-1'}, 'text': 'mdi-counter'},
                                                            {'component': 'span', 'text': '签到天数'}
                                                        ]
                                                    },
                                                    {
                                                        'component': 'th',
                                                        'props': {
                                                            'class': 'text-center text-body-1 font-weight-bold'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'warning', 'size': 'small', 'class': 'mr-1'}, 'text': 'mdi-pill'},
                                                            {'component': 'span', 'text': '剩余药丸'}
                                                        ]
                                                    }
                                                ]
                                            }
                                        ]
                                    },
                                    {
                                        'component': 'tbody',
                                        'content': [
                                            {
                                                'component': 'tr',
                                                'props': {
                                                    'class': 'text-sm'
                                                },
                                                'content': [
                                                    {
                                                        'component': 'td',
                                                        'props': {
                                                            'class': 'text-center text-high-emphasis'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'info', 'size': 'x-small', 'class': 'mr-1'}, 'text': 'mdi-clock-time-four-outline'},
                                                            {'component': 'span', 'text': history.get("date", "")}
                                                        ]
                                                    },
                                                    {
                                                        'component': 'td',
                                                        'props': {
                                                            'class': 'text-center text-high-emphasis'
                                                        },
                                                        'content': [
                                                            {
                                                                'component': 'VChip',
                                                                'props': {
                                                                    'color': 'success',
                                                                    'size': 'small',
                                                                    'variant': 'tonal',
                                                                },
                                                                'content': [
                                                                    {
                                                                        'component': 'VIcon',
                                                                        'props': {
                                                                            'size': 'small',
                                                                            'start': True
                                                                        },
                                                                        'text': 'mdi-check-circle'
                                                                    },
                                                                    {
                                                                        'component': 'span',
                                                                        'text': '已签到'
                                                                    }
                                                                ]
                                                            }
                                                        ]
                                                    },
                                                    {
                                                        'component': 'td',
                                                        'props': {
                                                            'class': 'text-center text-high-emphasis'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'info', 'size': 'x-small', 'class': 'mr-1'}, 'text': 'mdi-counter'},
                                                            {'component': 'span', 'text': f"{history.get('totalContinuousCheckIn', 0)}天"}
                                                        ]
                                                    },
                                                    {
                                                        'component': 'td',
                                                        'props': {
                                                            'class': 'text-center text-high-emphasis'
                                                        },
                                                        'content': [
                                                            {'component': 'VIcon', 'props': {'color': 'warning', 'size': 'x-small', 'class': 'mr-1'}, 'text': 'mdi-pill'},
                                                            {'component': 'span', 'text': f"{history.get('money', 0)}个"}
                                                        ]
                                                    }
                                                ]
                                            } for history in historys
                                        ]
                                    }
                                ]
                            },
                            {
                                'component': 'div',
                                'props': {
                                    'class': 'text-caption text-grey mt-2',
                                    'style': 'background: #f5f5f7; border-radius: 8px; padding: 6px 12px; display: inline-block;'
                                },
                                'content': [
                                    {'component': 'VIcon', 'props': {'size': 'x-small', 'class': 'mr-1'}, 'text': 'mdi-format-list-bulleted'},
                                    {'component': 'span', 'text': f'共显示 {len(historys)} 条签到记录'}
                                ]
                            }
                        ]
                    }
                ]
            }
        ]

    def stop_service(self):
        """退出插件"""
        try:
            if self._scheduler:
                self._scheduler.remove_all_jobs()
                if self._scheduler.running:
                    self._scheduler.shutdown()
                self._scheduler = None
        except Exception as e:
            logger.error("退出插件失败：%s" % str(e))
