#!/usr/bin/env python3
"""
Leaflow 多账号自动签到脚本
变量名：LEAFLOW_ACCOUNTS
变量值：邮箱1:密码1,邮箱2:密码2,邮箱3:密码3
"""

import os
import time
import logging
import traceback
from selenium.common.exceptions import TimeoutException
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
import requests
from datetime import datetime

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class LeaflowAutoCheckin:
    def __init__(self, email, password):
        self.email = email
        self.password = password
        
        if not self.email or not self.password:
            raise ValueError("邮箱和密码不能为空")
        
        self.driver = None
        self.setup_driver()
    
    def setup_driver(self):
        """设置Chrome驱动选项"""
        chrome_options = Options()
        
        # 基础稳定配置（适用于所有环境）
        chrome_options.add_argument('--disable-blink-features=AutomationControlled')
        chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
        chrome_options.add_experimental_option('useAutomationExtension', False)
        
        # 增强稳定性的通用选项
        chrome_options.add_argument('--disable-gpu')  # 禁用GPU加速，减少渲染问题
        chrome_options.add_argument('--disable-dev-shm-usage')  # 禁用/dev/shm使用，避免内存问题
        chrome_options.add_argument('--no-sandbox')  # 禁用沙箱，提高兼容性
        chrome_options.add_argument('--disable-extensions')  # 禁用扩展，减少干扰
        chrome_options.add_argument('--disable-plugins')  # 禁用插件，减少资源占用
        chrome_options.add_argument('--disable-images')  # 禁用图片加载，提高页面加载速度
        # chrome_options.add_argument('--disable-javascript')  # 启用JavaScript，签到页面功能依赖它
        chrome_options.add_argument('--window-size=1920,1080')  # 设置窗口大小
        chrome_options.add_argument('--ignore-certificate-errors')  # 忽略证书错误
        chrome_options.add_argument('--ignore-ssl-errors')  # 忽略SSL错误
        chrome_options.add_argument('--allow-insecure-localhost')  # 允许不安全的localhost连接
        chrome_options.add_argument('--log-level=3')  # 减少Chrome日志输出
        
        # 优化资源占用的选项
        chrome_options.add_argument('--disable-background-timer-throttling')  # 禁用后台定时器节流
        chrome_options.add_argument('--disable-backgrounding-occluded-windows')  # 禁用后台遮挡窗口
        chrome_options.add_argument('--disable-renderer-backgrounding')  # 禁用渲染器后台处理
        chrome_options.add_argument('--disable-translate')  # 禁用翻译
        chrome_options.add_argument('--disable-notifications')  # 禁用通知
        chrome_options.add_argument('--disable-popup-blocking')  # 禁用弹窗拦截
        chrome_options.add_argument('--disable-default-apps')  # 禁用默认应用
        chrome_options.add_argument('--disable-sync')  # 禁用同步
        chrome_options.add_argument('--disable-logging')  # 禁用日志
        chrome_options.add_argument('--disable-software-rasterizer')  # 禁用软件光栅化
        chrome_options.add_argument('--disable-features=site-per-process')  # 禁用站点隔离
        chrome_options.add_argument('--js-flags=--max-old-space-size=256')  # 限制JavaScript内存使用
        
        # GitHub Actions环境配置
        if os.getenv('GITHUB_ACTIONS'):
            chrome_options.add_argument('--headless')  # 无头模式
            chrome_options.add_argument('--disable-features=VizDisplayCompositor')  # 增强无头模式稳定性
            chrome_options.add_argument('--headless=new')  # 使用新的无头模式
            logger.info("已启用GitHub Actions环境配置")
        
        # 使用 webdriver-manager 自动获取匹配的 ChromeDriver
        try:
            from webdriver_manager.chrome import ChromeDriverManager
            from selenium.webdriver.chrome.service import Service
            
            # 尝试获取当前Chrome版本并使用匹配的ChromeDriver
            try:
                import subprocess
                chrome_version = subprocess.check_output(
                    ["google-chrome", "--version"]
                ).decode("utf-8").strip()
                major_version = chrome_version.split(" ")[2].split(".")[0]
                logger.info(f"检测到Chrome版本: {chrome_version}")
                logger.info(f"使用ChromeDriver主版本: {major_version}")
                
                service = Service(ChromeDriverManager(driver_version=major_version).install())
                self.driver = webdriver.Chrome(service=service, options=chrome_options)
                
                # 验证ChromeDriver版本
                chromedriver_version = self.driver.capabilities['chrome']['chromedriverVersion'].split(' ')[0]
                logger.info(f"已使用ChromeDriver版本: {chromedriver_version}")
                
            except Exception as e:
                logger.warning(f"获取Chrome版本失败，使用默认配置: {e}")
                service = Service(ChromeDriverManager().install())
                self.driver = webdriver.Chrome(service=service, options=chrome_options)
                
        except Exception as e:
            logger.warning(f"webdriver-manager 获取 ChromeDriver 失败，使用默认配置: {e}")
            self.driver = webdriver.Chrome(options=chrome_options)
        
        self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
        
        # 设置默认超时时间
        try:
            self.driver.set_page_load_timeout(60)  # 页面加载超时
            self.driver.set_script_timeout(60)  # 脚本执行超时
            logger.info(f"已设置超时时间: 页面加载60秒，脚本执行60秒")
        except Exception as e:
            logger.warning(f"设置超时时间时出错: {e}")
        
        # 移除隐式等待，仅使用显式等待
        # self.driver.implicitly_wait(5)
        logger.info("浏览器驱动初始化完成")
        
    def close_popup(self):
        """关闭初始弹窗"""
        try:
            logger.info("尝试关闭初始弹窗...")
            time.sleep(3)  # 等待弹窗加载
            
            # 尝试关闭弹窗
            try:
                actions = ActionChains(self.driver)
                actions.move_by_offset(10, 10).click().perform()
                logger.info("已成功关闭弹窗")
                time.sleep(2)
                return True
            except:
                pass
            return False
            
        except Exception as e:
            logger.warning(f"关闭弹窗时出错: {e}")
            return False
    
    def wait_for_element_clickable(self, by, value, timeout=10):
        """等待元素可点击"""
        return WebDriverWait(self.driver, timeout).until(
            EC.element_to_be_clickable((by, value))
        )
    
    def wait_for_element_present(self, by, value, timeout=10):
        """等待元素出现"""
        return WebDriverWait(self.driver, timeout).until(
            EC.presence_of_element_located((by, value))
        )
    
    def login(self):
        """执行登录流程"""
        logger.info(f"开始登录流程")
        
        # 访问登录页面
        self.driver.get("https://leaflow.net/login")
        time.sleep(5)
        
        # 关闭弹窗
        self.close_popup()
        
        # 输入邮箱
        try:
            logger.info("查找邮箱输入框...")
            
            # 等待页面稳定
            time.sleep(2)
            
            # 尝试多种选择器找到邮箱输入框
            email_selectors = [
                "input[type='text']",
                "input[type='email']", 
                "input[placeholder*='邮箱']",
                "input[placeholder*='邮件']",
                "input[placeholder*='email']",
                "input[name='email']",
                "input[name='username']"
            ]
            
            email_input = None
            for selector in email_selectors:
                try:
                    email_input = self.wait_for_element_clickable(By.CSS_SELECTOR, selector, 5)
                    logger.info(f"找到邮箱输入框")
                    break
                except:
                    continue
            
            if not email_input:
                raise Exception("找不到邮箱输入框")
            
            # 清除并输入邮箱
            email_input.clear()
            email_input.send_keys(self.email)
            logger.info("邮箱输入完成")
            time.sleep(2)
            
        except Exception as e:
            logger.error(f"输入邮箱时出错: {e}")
            # 尝试使用JavaScript直接设置值
            try:
                self.driver.execute_script(f"document.querySelector('input[type=\"text\"], input[type=\"email\"]').value = '{self.email}';")
                logger.info("通过JavaScript设置邮箱")
                time.sleep(2)
            except:
                raise Exception(f"无法输入邮箱: {e}")
        
        # 等待密码输入框出现并输入密码
        try:
            logger.info("查找密码输入框...")
            
            # 等待密码框出现
            password_input = self.wait_for_element_clickable(
                By.CSS_SELECTOR, "input[type='password']", 10
            )
            
            password_input.clear()
            password_input.send_keys(self.password)
            logger.info("密码输入完成")
            time.sleep(1)
            
        except TimeoutException:
            raise Exception("找不到密码输入框")
        
        # 点击登录按钮
        try:
            logger.info("查找登录按钮...")
            login_btn_selectors = [
                "//button[contains(text(), '登录')]",
                "//button[contains(text(), 'Login')]",
                "//button[@type='submit']",
                "//input[@type='submit']",
                "button[type='submit']"
            ]
            
            login_btn = None
            for selector in login_btn_selectors:
                try:
                    if selector.startswith("//"):
                        login_btn = self.wait_for_element_clickable(By.XPATH, selector, 5)
                    else:
                        login_btn = self.wait_for_element_clickable(By.CSS_SELECTOR, selector, 5)
                    logger.info(f"找到登录按钮")
                    break
                except:
                    continue
            
            if not login_btn:
                raise Exception("找不到登录按钮")
            
            login_btn.click()
            logger.info("已点击登录按钮")
            
        except Exception as e:
            raise Exception(f"点击登录按钮失败: {e}")
        
        # 等待登录完成
        try:
            WebDriverWait(self.driver, 20).until(
                lambda driver: "dashboard" in driver.current_url or "workspaces" in driver.current_url or "login" not in driver.current_url
            )
            
            # 检查当前URL确认登录成功
            current_url = self.driver.current_url
            if "dashboard" in current_url or "workspaces" in current_url or "login" not in current_url:
                logger.info(f"登录成功，当前URL: {current_url}")
                
                # 获取并保存登录后的COOKIE
                logger.info("获取登录后的COOKIE...")
                self.login_cookies = self.driver.get_cookies()
                logger.info(f"获取到 {len(self.login_cookies)} 个COOKIE")
                for cookie in self.login_cookies:
                    logger.debug(f"COOKIE: {cookie['name']} -> {cookie['domain']}")
                    
                return True
            else:
                raise Exception("登录后未跳转到正确页面")
                
        except TimeoutException:
            # 检查是否登录失败
            try:
                error_selectors = [".error", ".alert-danger", "[class*='error']", "[class*='danger']"]
                for selector in error_selectors:
                    try:
                        error_msg = self.driver.find_element(By.CSS_SELECTOR, selector)
                        if error_msg.is_displayed():
                            raise Exception(f"登录失败: {error_msg.text}")
                    except:
                        continue
                raise Exception("登录超时，无法确认登录状态")
            except Exception as e:
                raise e
    
    def get_balance(self):
        """获取当前账号的总余额"""
        try:
            logger.info("获取账号余额...")
            
            # 跳转到仪表板页面
            self.driver.get("https://leaflow.net/dashboard")
            time.sleep(3)
            
            # 等待页面加载
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.TAG_NAME, "body"))
            )
            
            # 尝试多种选择器查找余额元素
            balance_selectors = [
                "//*[contains(text(), '¥') or contains(text(), '￥') or contains(text(), '元')]",
                "//*[contains(@class, 'balance')]",
                "//*[contains(@class, 'money')]",
                "//*[contains(@class, 'amount')]",
                "//button[contains(@class, 'dollar')]",
                "//span[contains(@class, 'font-medium')]"
            ]
            
            for selector in balance_selectors:
                try:
                    elements = self.driver.find_elements(By.XPATH, selector)
                    for element in elements:
                        text = element.text.strip()
                        # 查找包含数字和货币符号的文本
                        if any(char.isdigit() for char in text) and ('¥' in text or '￥' in text or '元' in text):
                            # 提取数字部分
                            import re
                            numbers = re.findall(r'\d+\.?\d*', text)
                            if numbers:
                                balance = numbers[0]
                                logger.info(f"找到余额: {balance}元")
                                return f"{balance}元"
                except:
                    continue
            
            logger.warning("未找到余额信息")
            return "未知"
            
        except Exception as e:
            logger.warning(f"获取余额时出错: {e}")
            return "未知"
    
    def wait_for_checkin_page_loaded(self, max_retries=5, wait_time=30):
        """等待签到页面完全加载，支持重试"""

        for attempt in range(max_retries):
            logger.info(f"等待签到页面加载，尝试 {attempt + 1}/{max_retries}")
            
            # 收集页面基本信息，便于调试
            logger.info(f"  当前页面URL: {self.driver.current_url}")
            logger.info(f"  当前页面标题: {self.driver.title}")
            
            try:
                # 检查页面是否包含签到相关元素
                # 使用组合等待条件：DOM就绪 + 核心元素可见
                WebDriverWait(self.driver, wait_time).until(
                    lambda d: d.execute_script("return document.readyState") == "complete"
                )
            
                checkin_indicators = [
                    (By.CSS_SELECTOR, "button.checkin-btn"),  # 首选精确选择器
                    (By.XPATH, "//button[contains(text(), '立即签到')]"),
                    (By.XPATH, "//button[contains(text(), '已签到')]"),
                    (By.XPATH, "//button[contains(text(), '已完成')]"),
                    (By.XPATH, "//*[contains(text(), '每日签到')]"),
                    (By.XPATH, "//*[contains(text(), '签到')]")
                ]
                
                for locator_type, selector in checkin_indicators:
                    try:
                        # 增加元素等待时间
                        element = WebDriverWait(self.driver, 15).until(
                            EC.visibility_of_element_located((locator_type, selector))
                        )
                        
                        # 只要找到可见的签到相关元素，不管是否可用，都认为页面已加载成功
                        # 已签到状态下的按钮可能是禁用的，所以不能用is_enabled()判断
                        logger.info(f"检测到签到元素: {selector}")
                        logger.info(f"  元素可见性: {element.is_displayed()}")
                        logger.info(f"  元素可用性: {'启用' if element.is_enabled() else '禁用'}")
                        logger.info(f"  元素文本: '{element.text.strip()}'")
                        return True
                    except TimeoutException:
                        logger.debug(f"元素定位失败: {selector}，尝试下个策略")
                        continue
                
                logger.warning(f"第 {attempt + 1} 次尝试未找到签到相关元素")
                
                # 尝试获取页面源代码的前2000个字符，便于调试
                try:
                    page_source = self.driver.page_source[:2000]
                    logger.debug(f"页面源码片段: {page_source}...")
                except Exception as e:
                    logger.error(f"获取页面源码失败: {e}")
                
            except TimeoutException:
                logger.error(f"页面加载超时，重试中... (尝试 {attempt+1})")
            except Exception as e:
                logger.critical(f"严重错误: {str(e)}")
                logger.error(f"错误详情: {traceback.format_exc()}")
                if "net::ERR" in str(e):
                    logger.info("检测到网络错误，立即重试")
                    continue
        
        return False
    
    def find_and_click_checkin_button(self):
        """查找并点击签到按钮 - 处理已签到状态"""
        logger.info("开始查找签到按钮...")
        start_time = time.time()
        
        try:
            # 收集页面基本信息
            logger.info(f"当前页面URL: {self.driver.current_url}")
            logger.info(f"当前页面标题: {self.driver.title}")
            
            # 先等待页面可能的重载
            logger.info("等待页面稳定...")
            time.sleep(5)
            
            # 使用和单账号成功时相同的选择器
            checkin_selectors = [
                "button.checkin-btn",
                "//button[contains(text(), '立即签到')]",
                "//button[contains(@class, 'checkin')]",
                "button[type='submit']",
                "button[name='checkin']"
            ]
            
            for selector in checkin_selectors:
                logger.info(f"尝试使用选择器: {selector}")
                try:
                    if selector.startswith("//"):
                        checkin_btn = WebDriverWait(self.driver, 15).until(
                            EC.presence_of_element_located((By.XPATH, selector))
                        )
                    else:
                        checkin_btn = WebDriverWait(self.driver, 15).until(
                            EC.presence_of_element_located((By.CSS_SELECTOR, selector))
                        )
                    
                    # 详细检查按钮状态
                    logger.info(f"找到按钮，开始检查状态...")
                    logger.info(f"按钮可见性: {checkin_btn.is_displayed()}")
                    logger.info(f"按钮可用性: {checkin_btn.is_enabled()}")
                    logger.info(f"按钮文本: '{checkin_btn.text.strip()}'")
                    
                    if checkin_btn.is_displayed():
                        # 检查按钮文本，如果包含"已签到"或"已完成"则说明今天已经签到过了
                        btn_text = checkin_btn.text.strip()
                        
                        # 检查页面上是否有"今日已签到"文本
                        page_text = self.driver.page_source
                        
                        # 综合判断已签到状态：按钮禁用或按钮文本包含"已完成"或页面包含"今日已签到"
                        if (not checkin_btn.is_enabled() or 
                            "已完成" in btn_text or 
                            "今日已签到" in page_text or
                            "已签到" in btn_text):
                            logger.info(f"今日已签到，状态信息：")
                            logger.info(f"  - 按钮状态: {'禁用' if not checkin_btn.is_enabled() else '可用'}")
                            logger.info(f"  - 按钮文本: '{btn_text}'")
                            logger.info(f"  - 页面包含'今日已签到': {'是' if '今日已签到' in page_text else '否'}")
                            return "already_checked_in"
                        
                        # 尝试多种点击方式
                        clicked = False
                        
                        # 方式1: JavaScript点击（优先使用，避免页面阻塞）
                        try:
                            logger.info("方式1: 尝试JavaScript点击...")
                            self.driver.execute_script("arguments[0].click();", checkin_btn)
                            clicked = True
                            logger.info("方式1: JavaScript点击成功")
                        except Exception as e:
                            logger.warning(f"方式1: JavaScript点击失败: {e}")
                            clicked = False
                        
                        # 方式2: ActionChains点击
                        if not clicked:
                            try:
                                logger.info("方式2: 尝试ActionChains点击...")
                                # 设置隐式等待时间，避免点击超时
                                self.driver.implicitly_wait(5)
                                actions = ActionChains(self.driver)
                                actions.move_to_element(checkin_btn).click().perform()
                                clicked = True
                                logger.info("方式2: ActionChains点击成功")
                            except Exception as e:
                                logger.warning(f"方式2: ActionChains点击失败: {e}")
                                clicked = False
                            finally:
                                # 恢复隐式等待时间
                                self.driver.implicitly_wait(0)
                        
                        # 方式3: 直接点击（最后尝试，可能会阻塞）
                        if not clicked:
                            try:
                                logger.info("方式3: 尝试直接点击按钮...")
                                # 使用WebDriverWait设置点击超时
                                WebDriverWait(self.driver, 10).until(
                                    EC.element_to_be_clickable((By.CSS_SELECTOR, "button.checkin-btn"))
                                ).click()
                                clicked = True
                                logger.info("方式3: 直接点击成功")
                            except Exception as e:
                                logger.warning(f"方式3: 直接点击失败: {e}")
                                clicked = False
                        
                        if clicked:
                            logger.info(f"成功点击签到按钮，耗时: {time.time() - start_time:.2f}秒")
                            # 点击后立即检查页面变化，确认签到是否成功
                            time.sleep(2)
                            # 检查按钮状态或页面文本变化
                            try:
                                updated_btn = self.driver.find_element(By.CSS_SELECTOR, "button.checkin-btn")
                                updated_text = updated_btn.text.strip()
                                page_text = self.driver.page_source
                                if (not updated_btn.is_enabled() or 
                                    "已完成" in updated_text or 
                                    "今日已签到" in page_text or
                                    "已签到" in updated_text):
                                    logger.info("签到成功，按钮状态已更新")
                            except:
                                pass
                            return True
                        else:
                            logger.error("所有点击方式均失败")
                            return False
                    else:
                        logger.warning("按钮不可见")
                        continue
                        
                except Exception as e:
                    logger.debug(f"选择器{selector}未找到按钮: {e}")
                    continue
            
            logger.error("遍历所有选择器后仍未找到可点击的签到按钮")
            return False
                    
        except Exception as e:
            logger.error(f"查找签到按钮时出错: {e}")
            logger.error(f"错误详情: {traceback.format_exc()}")
            return False
    
    def checkin(self):
        """执行签到流程"""
        logger.info("执行签到流程...")
        
        # 跳转到签到页面
        logger.info("跳转到签到页面...")
        
        # 只使用明确的签到页面URL，避免跳转到登录页面
        target_url = "https://checkin.leaflow.net/index.php"
        
        # 网络状态检查
        try:
            import socket
            socket.create_connection(("checkin.leaflow.net", 443), timeout=10)
            logger.info("网络连接正常，可以访问签到服务器")
        except Exception as net_e:
            logger.warning(f"网络连接检查失败: {net_e}，可能网络不稳定")
        
        # 尝试访问签到页面，处理网络超时
        max_retries = 8
        retry_delay = 3
        start_time = time.time()
        
        for attempt in range(1, max_retries + 1):
            try:
                logger.info(f"尝试第 {attempt}/{max_retries} 次访问签到页面...")
                logger.info(f"当前耗时: {time.time() - start_time:.2f} 秒")
                
                # 重置超时设置，使用更长的超时时间
                try:
                    self.driver.set_page_load_timeout(120)
                    self.driver.set_script_timeout(60)
                    logger.debug("已重置超时设置: 页面加载120秒，脚本执行60秒")
                except Exception as timeout_e:
                    logger.warning(f"重置超时设置时出错: {timeout_e}")
                
                # 记录开始访问时间
                access_start = time.time()
                logger.info(f"尝试访问URL: {target_url}")
                self.driver.get(target_url)
                access_time = time.time() - access_start
                logger.info(f"页面访问耗时: {access_time:.2f} 秒")
                
                # 检查当前URL和页面状态
                current_url = self.driver.current_url
                logger.info(f"当前URL: {current_url}")
                
                # 获取页面标题
                try:
                    page_title = self.driver.title
                    logger.info(f"当前页面标题: {page_title}")
                except Exception as title_e:
                    logger.warning(f"获取页面标题失败: {title_e}")
                
                # 检查是否跳转到了登录页面
                if "login" in current_url and "checkin" not in current_url:
                    logger.warning(f"访问签到页面时跳转到了登录页面: {current_url}")
                    logger.info("跳过登录页面，继续执行COOKIE处理...")
                else:
                    logger.info(f"成功访问签到页面，URL: {current_url}")
                
                # 检查页面加载状态
                try:
                    page_state = self.driver.execute_script("return document.readyState")
                    logger.info(f"页面加载状态: {page_state}")
                    if page_state != "complete":
                        logger.warning("页面可能未完全加载，准备继续处理")
                except Exception as state_e:
                    logger.warning(f"获取页面状态失败: {state_e}")
                
                break
                
            except Exception as e:
                error_msg = str(e)
                logger.warning(f"访问URL {target_url}失败: {error_msg}")
                logger.debug(f"错误详情: {traceback.format_exc()}")
                
                # 增强错误分类处理
                error_lower = error_msg.lower()
                if any(keyword in error_lower for keyword in [
                    "-0.005", "-0.004", "timed out receiving message from renderer",
                    "timeout: timed out", "session not created", "chrome not reachable",
                    "no such session", "session deleted", "connection refused"
                ]):
                    logger.error("检测到ChromeDriver兼容性错误，重置浏览器会话...")
                    try:
                        self.driver.quit()
                        logger.info("已关闭旧的浏览器会话")
                    except Exception as quit_e:
                        logger.warning(f"关闭浏览器会话失败: {quit_e}")
                    
                    # 重置浏览器会话
                    try:
                        self.setup_driver()
                        logger.info("浏览器会话已重置，准备重试")
                    except Exception as setup_e:
                        logger.error(f"重置浏览器会话失败: {setup_e}")
                        raise Exception(f"无法重置浏览器会话: {setup_e}")
                
                elif "net::err" in error_lower:
                    logger.warning(f"网络错误 ({error_msg})，可能需要检查网络连接")
                    # 网络错误时增加等待时间
                    retry_delay = 5
                elif "connection timed out" in error_lower or "timed out" in error_lower:
                    logger.warning(f"连接超时 ({error_msg})，可能网络延迟较高")
                elif "dns_probe_finished_nxdomain" in error_lower:
                    logger.warning("DNS解析失败，可能是域名问题")
                else:
                    logger.warning(f"其他错误: {error_msg}")
                
                # 等待后重试，使用指数退避
                if attempt < max_retries:
                    wait_time = retry_delay * (2 ** (attempt - 1))  # 使用2倍指数退避
                    wait_time = min(wait_time, 60)  # 最大等待60秒
                    logger.info(f"等待 {wait_time:.1f} 秒后重试...")
                    time.sleep(wait_time)
                else:
                    total_time = time.time() - start_time
                    logger.error(f"经过 {max_retries} 次重试后仍无法访问签到页面，总耗时: {total_time:.2f} 秒")
                    raise Exception(f"无法访问签到页面: {error_msg}")
        
        # 添加登录时保存的COOKIE到当前域名
        logger.info("添加登录COOKIE到checkin域名...")
        if hasattr(self, 'login_cookies') and self.login_cookies:
            # 先清除当前页面的COOKIE
            self.driver.delete_all_cookies()
            
            # 添加登录时保存的所有COOKIE
            for cookie in self.login_cookies:
                try:
                    # 适配不同域名的COOKIE
                    cookie_copy = cookie.copy()
                    # 确保COOKIE能被所有子域名使用
                    if 'domain' not in cookie_copy or not cookie_copy['domain']:
                        cookie_copy['domain'] = '.leaflow.net'
                    # 移除可能导致问题的属性
                    if 'expiry' in cookie_copy and isinstance(cookie_copy['expiry'], float):
                        cookie_copy['expiry'] = int(cookie_copy['expiry'])
                    # 添加COOKIE
                    self.driver.add_cookie(cookie_copy)
                    logger.debug(f"添加COOKIE成功: {cookie['name']} -> {cookie_copy.get('domain', '无域名')}")
                except Exception as e:
                    logger.debug(f"添加COOKIE失败: {cookie['name']} -> {e}")
            
            # 尝试直接访问签到首页，使用明确的URL
            logger.info("COOKIE添加完成，直接访问签到首页...")
            try:
                # 使用明确的URL，避免重定向，增加超时时间
                self.driver.set_page_load_timeout(60)
                self.driver.get(target_url)
                logger.info(f"成功访问签到首页，URL: {self.driver.current_url}")
            except Exception as e:
                logger.error(f"访问签到首页时出错: {e}")
                # 无论是否超时，都获取当前页面信息
                try:
                    logger.info(f"当前页面URL: {self.driver.current_url}")
                    logger.info(f"当前页面标题: {self.driver.title}")
                    # 获取页面源码（最多前2000字符）
                    page_source = self.driver.page_source[:2000]
                    logger.info(f"页面源码片段: {page_source}")
                except Exception as info_e:
                    logger.error(f"获取页面信息失败: {info_e}")
                
                # 获取当前页面信息，便于调试
                logger.info(f"当前签到页面URL: {self.driver.current_url}")
                logger.info(f"当前页面标题: {self.driver.title}")
                
                # 简化重定向处理，直接检查当前URL
                logger.info("检查当前页面状态...")
                
                # 检查是否需要进行OAuth授权
                if "oauth/authorize" in self.driver.current_url:
                    logger.info("检测到OAuth授权页面，尝试自动授权...")
                    # 查找并点击授权按钮
                    try:
                        # 尝试多种选择器找到授权按钮
                        authorize_selectors = [
                            "button[type='submit']",
                            "input[type='submit']",
                            "//button[contains(text(), '授权')]",
                            "//button[contains(text(), 'Authorize')]"
                        ]
                        
                        authorize_btn = None
                        for selector in authorize_selectors:
                            try:
                                if selector.startswith("//"):
                                    authorize_btn = WebDriverWait(self.driver, 10).until(
                                        EC.element_to_be_clickable((By.XPATH, selector))
                                    )
                                else:
                                    authorize_btn = WebDriverWait(self.driver, 10).until(
                                        EC.element_to_be_clickable((By.CSS_SELECTOR, selector))
                                    )
                                logger.info(f"找到授权按钮")
                                break
                            except:
                                continue
                        
                        if authorize_btn:
                            authorize_btn.click()
                            logger.info("已点击授权按钮")
                            time.sleep(5)
                            logger.info(f"授权后URL: {self.driver.current_url}")
                        else:
                            logger.warning("未找到授权按钮，尝试等待自动跳转...")
                            time.sleep(10)
                            logger.info(f"等待后URL: {self.driver.current_url}")
                    except Exception as e:
                        logger.warning(f"自动授权失败，可能需要手动授权: {e}")
                
                # 成功访问并处理完重定向，继续执行后续流程
                # 注意：这里不再需要continue或break，因为我们已经在前面的代码中处理了循环退出逻辑
                
            finally:
                # 恢复默认页面加载超时
                self.driver.set_page_load_timeout(60)
        
        # 等待签到页面加载（最多重试5次，每次等待20秒）
        retry_count = 0
        max_retries = 5
        success = False
        
        while retry_count < max_retries and not success:
            retry_count += 1
            logger.info(f"等待签到页面加载，尝试 {retry_count}/{max_retries}")
            
            # 检查当前URL和标题，记录详细信息
            current_url = self.driver.current_url
            current_title = self.driver.title
            logger.info(f"  当前URL: {current_url}")
            logger.info(f"  当前标题: {current_title}")
            
            # 检查是否是502错误
            if "502" in current_title or "Bad Gateway" in current_title:
                logger.error(f"第 {retry_count} 次尝试遇到502 Bad Gateway错误")
                
                # 尝试重新访问主站获取有效COOKIE（仅在需要时）
                logger.info("尝试重新访问主站获取有效COOKIE...")
                self.driver.get("https://leaflow.net/dashboard")
                time.sleep(3)
                
                # 重新跳转到签到页面
                self.driver.get("https://checkin.leaflow.net")
                time.sleep(5)
                continue
            
            # 检查是否是重定向到登录页面
            if "login" in current_url and "checkin" not in current_url:
                logger.error(f"第 {retry_count} 次尝试遇到登录页面，COOKIE可能失效")
                
                # 重新执行登录流程
                logger.info("尝试重新登录...")
                if self.login():
                    # 重新跳转到签到页面
                    self.driver.get("https://checkin.leaflow.net")
                    time.sleep(5)
                else:
                    raise Exception("重新登录失败")
                continue
            
            # 检查是否是OAuth回调页面
            if "auth_callback.php" in current_url:
                logger.info(f"第 {retry_count} 次尝试遇到OAuth回调页面，等待自动跳转...")
                time.sleep(5)
                logger.info(f"  自动跳转后URL: {self.driver.current_url}")
                logger.info(f"  自动跳转后标题: {self.driver.title}")
            
            # 尝试等待页面加载
            if self.wait_for_checkin_page_loaded(max_retries=1, wait_time=15):
                success = True
                logger.info(f"第 {retry_count} 次尝试成功加载签到页面")
            else:
                logger.warning(f"第 {retry_count} 次尝试未成功加载签到页面")
                
                # 尝试刷新页面
                logger.info("尝试刷新页面...")
                self.driver.refresh()
                time.sleep(5)
        
        if not success:
            raise Exception(f"签到页面加载失败，经过 {max_retries} 次重试后仍无法访问")
        
        # 查找并点击立即签到按钮
        checkin_result = self.find_and_click_checkin_button()
        
        if checkin_result == "already_checked_in":
            return "今日已签到"
        elif checkin_result is True:
            logger.info("已点击立即签到按钮")
            time.sleep(5)  # 等待签到结果
            
            # 获取签到结果
            result_message = self.get_checkin_result()
            return result_message
        else:
            raise Exception("找不到立即签到按钮或按钮不可点击")
    
    def get_checkin_result(self):
        """获取签到结果消息"""
        try:
            # 给页面一些时间显示结果
            time.sleep(3)
            
            # 尝试查找各种可能的成功消息元素
            success_selectors = [
                ".alert-success",
                ".success",
                ".message",
                "[class*='success']",
                "[class*='message']",
                ".modal-content",  # 弹窗内容
                ".ant-message",    # Ant Design 消息
                ".el-message",     # Element UI 消息
                ".toast",          # Toast消息
                ".notification"    # 通知
            ]
            
            for selector in success_selectors:
                try:
                    element = self.driver.find_element(By.CSS_SELECTOR, selector)
                    if element.is_displayed():
                        text = element.text.strip()
                        if text:
                            return text
                except:
                    continue
            
            # 如果没有找到特定元素，检查页面文本
            page_text = self.driver.find_element(By.TAG_NAME, "body").text
            important_keywords = ["成功", "签到", "获得", "恭喜", "谢谢", "感谢", "完成", "已签到", "连续签到"]
            
            for keyword in important_keywords:
                if keyword in page_text:
                    # 提取包含关键词的行
                    lines = page_text.split('\n')
                    for line in lines:
                        if keyword in line and len(line.strip()) < 100:  # 避免提取过长的文本
                            return line.strip()
            
            # 检查签到按钮状态变化
            try:
                checkin_btn = self.driver.find_element(By.CSS_SELECTOR, "button.checkin-btn")
                if not checkin_btn.is_enabled() or "已签到" in checkin_btn.text or "disabled" in checkin_btn.get_attribute("class"):
                    return "今日已签到完成"
            except:
                pass
            
            return "签到完成，但未找到具体结果消息"
            
        except Exception as e:
            return f"获取签到结果时出错: {str(e)}"
    
    def run(self):
        """单个账号执行流程"""
        try:
            logger.info(f"开始处理账号")
            
            # 登录
            if self.login():
                # 签到
                result = self.checkin()
                
                # 获取余额
                balance = self.get_balance()
                
                logger.info(f"签到结果: {result}, 余额: {balance}")
                return True, result, balance
            else:
                raise Exception("登录失败")
                
        except Exception as e:
            error_msg = f"自动签到失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg, "未知"
        
        finally:
            if self.driver:
                self.driver.quit()

class MultiAccountManager:
    """多账号管理器 - 简化配置版本"""
    
    def __init__(self):
        self.accounts = self.load_accounts()
    
    def load_accounts(self):
        """从环境变量加载多账号信息，支持冒号分隔多账号和单账号"""
        accounts = []
        
        logger.info("开始加载账号配置...")
        
        # 方法1: 冒号分隔多账号格式
        accounts_str = os.getenv('LEAFLOW_ACCOUNTS', '').strip()
        if accounts_str:
            try:
                logger.info("尝试解析冒号分隔多账号配置")
                account_pairs = [pair.strip() for pair in accounts_str.split(',')]
                
                logger.info(f"找到 {len(account_pairs)} 个账号")
                
                for i, pair in enumerate(account_pairs):
                    if ':' in pair:
                        email, password, token = pair.split(':', 1)
                        email = email.strip()
                        password = password.strip()
                        token = token.strip()
                        
                        if email and password:
                            accounts.append({
                                'email': email,
                                'password': password,
                                'token': token
                            })
                            logger.info(f"成功添加第 {i+1} 个账号")
                        else:
                            logger.warning(f"账号对格式错误")
                    else:
                        logger.warning(f"账号对缺少冒号分隔符")
                
                if accounts:
                    logger.info(f"从冒号分隔格式成功加载了 {len(accounts)} 个账号")
                    return accounts
                else:
                    logger.warning("冒号分隔配置中没有找到有效的账号信息")
            except Exception as e:
                logger.error(f"解析冒号分隔账号配置失败: {e}")
        
        # 方法2: 单账号格式
        single_email = os.getenv('LEAFLOW_EMAIL', '').strip()
        single_password = os.getenv('LEAFLOW_PASSWORD', '').strip()
        single_token = os.getenv('LEAFLOW_TOKEN', '').strip()
        if single_email and single_password:
            accounts.append({
                'email': single_email,
                'password': single_password,
                'token': single_token
            })
            logger.info("加载了单个账号配置")
            return accounts
        
        # 如果所有方法都失败
        logger.error("未找到有效的账号配置")
        logger.error("请检查以下环境变量设置:")
        logger.error("1. LEAFLOW_ACCOUNTS: 冒号分隔多账号 (email1:pass1,email2:pass2)")
        logger.error("2. LEAFLOW_EMAIL 和 LEAFLOW_PASSWORD: 单账号")
        
        raise ValueError("未找到有效的账号配置")
    
    def send_api_notification(self, message):
        """发送API通知"""
        try:
            url = "http://111.11.107.61:30005/send_private_msg"
            # 构建请求数据
            data = {
                "user_id": "8739050",
                "message": [{"type": "text", "data": {"text": message}}]
            }
            
            # 从环境变量读取token
            token = os.getenv('LEAFLOW_TOKEN', '').strip()
            headers = {
                "Authorization": f"{token}",
                "Content-Type": "application/json"
            }
            
            logger.info(f"正在发送API通知到 {url}")
            response = requests.post(url, json=data, headers=headers, timeout=10)
            
            logger.info(f"API通知发送结果 - 状态码: {response.status_code}, 响应: {response.text}")
            logger.info(f"✅ API通知发送成功") if response.status_code == 200 else logger.error(f"❌ API通知发送失败")
                
        except Exception as e:
            logger.error(f"❌ 发送API通知时出错: {e}")
            logger.error(f"错误详情: {traceback.format_exc()}")
    
    def send_notification(self, results):
        """发送API通知"""
        logger.info("开始发送API通知")
        # 确保总是发送API通知，即使发生异常
        try:
            # 构建通知消息
            success_count = sum(1 for _, success, _, _ in results if success)
            total_count = len(results)
            current_date = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
            
            # 构建API通知消息
            api_message = f"🎁 Leaflow自动签到通知\n"
            api_message += f"📊 成功: {success_count}/{total_count}\n"
            api_message += f"📅 签到时间：{current_date}\n\n"
            
            for email, success, result, balance in results:
                # 隐藏邮箱部分字符以保护隐私
                masked_email = email[:3] + "***" + email[email.find("@"):]
                
                if success:
                    status = "✅"
                    api_message += f"账号：{masked_email}\n"
                    api_message += f"{status}  {result}！\n"
                    api_message += f"💰  当前总余额：{balance}。\n\n"
                else:
                    status = "❌"
                    api_message += f"账号：{masked_email}\n"
                    api_message += f"{status}  {result}\n\n"
            
            # 发送API通知
            logger.info("准备发送API通知")
            self.send_api_notification(api_message)
            logger.info("API通知发送完成")
            
        except Exception as e:
            logger.error(f"构建API通知消息时出错: {e}")
            logger.error(f"错误详情: {traceback.format_exc()}")
            # 即使发生异常，也要尝试发送基本的API通知
            try:
                success_count = sum(1 for _, success, _, _ in results if success)
                total_count = len(results)
                basic_message = f"签到任务完成，成功{success_count}个，失败{total_count - success_count}个"
                logger.info(f"尝试发送基本API通知: {basic_message}")
                self.send_api_notification(basic_message)
            except Exception as e2:
                logger.error(f"发送基本API通知时出错: {e2}")
                logger.error(f"错误详情: {traceback.format_exc()}")
    
    def run_all(self):
        """运行所有账号的签到流程"""
        logger.info(f"开始执行 {len(self.accounts)} 个账号的签到任务")
        
        results = []
        
        for i, account in enumerate(self.accounts, 1):
            logger.info(f"处理第 {i}/{len(self.accounts)} 个账号")
            
            try:
                auto_checkin = LeaflowAutoCheckin(account['email'], account['password'])
                success, result, balance = auto_checkin.run()
                results.append((account['email'], success, result, balance))
                
                # 在账号之间添加间隔，避免请求过于频繁
                if i < len(self.accounts):
                    wait_time = 5
                    logger.info(f"等待{wait_time}秒后处理下一个账号...")
                    time.sleep(wait_time)
                    
            except Exception as e:
                error_msg = f"处理账号时发生异常: {str(e)}"
                logger.error(error_msg)
                results.append((account['email'], False, error_msg, "未知"))
        
        # 发送第一次汇总通知
        self.send_notification(results)
        
        # 暂时关闭30分钟后重试功能
        # 检查是否有失败的账号需要重试
        # failed_accounts = [account for account, (email, success, _, _) in zip(self.accounts, results) if not success]
        # if failed_accounts:
        #     logger.info(f"发现 {len(failed_accounts)} 个账号签到失败，将在30分钟后重试...")
        #     
        #     # 等待30分钟
        #     retry_wait_time = 30 * 60
        #     logger.info(f"等待{retry_wait_time}秒后重试失败的账号...")
        #     time.sleep(retry_wait_time)
        #     
        #     # 重试失败的账号
        #     retry_results = []
        #     for i, account in enumerate(failed_accounts, 1):
        #         logger.info(f"重试第 {i}/{len(failed_accounts)} 个失败账号")
        #         
        #         try:
        #             auto_checkin = LeaflowAutoCheckin(account['email'], account['password'])
        #             success, result, balance = auto_checkin.run()
        #             retry_results.append((account['email'], success, result, balance))
        #             
        #             # 在账号之间添加间隔
        #             if i < len(failed_accounts):
        #                 wait_time = 5
        #                 logger.info(f"等待{wait_time}秒后处理下一个重试账号...")
        #                 time.sleep(wait_time)
        #                 
        #         except Exception as e:
        #             error_msg = f"重试账号时发生异常: {str(e)}"
        #             logger.error(error_msg)
        #             retry_results.append((account['email'], False, error_msg, "未知"))
        #     
        #     # 发送重试结果通知
        #     if retry_results:
        #         # 构建重试通知消息
        #         retry_success_count = sum(1 for _, success, _, _ in retry_results if success)
        #         retry_total_count = len(retry_results)
        #         current_date = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
        #         
        #         retry_message = f"🔄 Leaflow自动签到重试通知\n"
        #         retry_message += f"📊 重试成功: {retry_success_count}/{retry_total_count}\n"
        #         retry_message += f"📅 重试时间：{current_date}\n\n"
        #         
        #         for email, success, result, balance in retry_results:
        #             masked_email = email[:3] + "***" + email[email.find("@"):]
        #             
        #             if success:
        #                 status = "✅"
        #                 retry_message += f"账号：{masked_email}\n"
        #                 retry_message += f"{status}  重试成功！{result}\n"
        #                 retry_message += f"💰  当前总余额：{balance}。\n\n"
        #             else:
        #                 status = "❌"
        #                 retry_message += f"账号：{masked_email}\n"
        #                 retry_message += f"{status}  重试失败：{result}\n\n"
        #         
        #         # 发送重试通知
        #         logger.info("发送重试结果通知...")
        #         self.send_api_notification(retry_message)
        #         
        #         # 更新原始结果
        #         for email, success, result, balance in retry_results:
        #             for i, (orig_email, orig_success, orig_result, orig_balance) in enumerate(results):
        #                 if orig_email == email:
        #                     results[i] = (email, success, result, balance)
        #                     break
        
        # 返回总体结果
        success_count = sum(1 for _, success, _, _ in results if success)
        return success_count == len(self.accounts), results

def main():
    """主函数"""
    try:
        manager = MultiAccountManager()
        overall_success, detailed_results = manager.run_all()
        
        if overall_success:
            logger.info("✅ 所有账号签到成功")
            exit(0)
        else:
            success_count = sum(1 for _, success, _, _ in detailed_results if success)
            logger.warning(f"⚠️ 部分账号签到失败: {success_count}/{len(detailed_results)} 成功")
            # 即使有失败，也不退出错误状态，因为可能部分成功
            exit(0)
            
    except Exception as e:
        logger.error(f"❌ 脚本执行出错: {e}")
        exit(1)

if __name__ == "__main__":
    main()
