"""
验证码处理模块
支持验证码识别和处理辅助
"""
import asyncio
from typing import Optional, Tuple
from pathlib import Path
from playwright.async_api import Page
from loguru import logger
from dataclasses import dataclass


@dataclass
class CaptchaResult:
    """验证码识别结果"""
    success: bool
    text: Optional[str] = None
    confidence: float = 0.0
    error: Optional[str] = None


class CaptchaHandler:
    """
    验证码处理器
    提供验证码识别和处理辅助功能
    """
    
    def __init__(self, page: Page):
        self.page = page
        self._2captcha_api_key: Optional[str] = None
    
    def set_2captcha_key(self, api_key: str):
        """设置2Captcha API密钥"""
        self._2captcha_api_key = api_key
    
    async def save_captcha_image(
        self,
        selector: str,
        output_path: str = "captcha.png",
    ) -> bool:
        """
        保存验证码图片
        
        Args:
            selector: 验证码图片选择器
            output_path: 输出路径
            
        Returns:
            bool: 是否成功
        """
        try:
            element = self.page.locator(selector)
            await element.screenshot(path=output_path)
            logger.info(f"验证码图片已保存: {output_path}")
            return True
        except Exception as e:
            logger.error(f"保存验证码图片失败: {e}")
            return False
    
    async def recognize_with_2captcha(
        self,
        image_path: str,
        timeout: int = 120,
    ) -> CaptchaResult:
        """
        使用2Captcha识别验证码
        
        Args:
            image_path: 图片路径
            timeout: 超时时间
            
        Returns:
            CaptchaResult: 识别结果
        """
        if not self._2captcha_api_key:
            return CaptchaResult(
                success=False,
                error="未设置2Captcha API密钥",
            )
        
        try:
            import base64
            from pathlib import Path
            
            # 读取图片并转base64
            image_data = base64.b64encode(Path(image_path).read_bytes()).decode()
            
            # 提交到2Captcha
            # 这里只是示例，实际需要调用2Captcha API
            logger.info("提交验证码到2Captcha...")
            
            # 模拟识别结果
            # 实际使用时需要实现完整的API调用
            await asyncio.sleep(2)
            
            return CaptchaResult(
                success=True,
                text="demo_result",
                confidence=0.9,
            )
            
        except Exception as e:
            return CaptchaResult(
                success=False,
                error=str(e),
            )
    
    async def recognize_image(
        self,
        image_path: str,
        method: str = "local",
    ) -> CaptchaResult:
        """
        本地图片验证码识别（需要OCR库）
        
        Args:
            image_path: 图片路径
            method: 识别方法
            
        Returns:
            CaptchaResult: 识别结果
        """
        try:
            # 尝试使用pytesseract
            try:
                import pytesseract
                from PIL import Image
                
                image = Image.open(image_path)
                text = pytesseract.image_to_string(image, config='--psm 7')
                text = text.strip()
                
                if text:
                    return CaptchaResult(
                        success=True,
                        text=text,
                        confidence=0.8,
                    )
                else:
                    return CaptchaResult(
                        success=False,
                        error="OCR未能识别出文本",
                    )
                    
            except ImportError:
                return CaptchaResult(
                    success=False,
                    error="需要安装pytesseract和PIL: pip install pytesseract pillow",
                )
                
        except Exception as e:
            return CaptchaResult(
                success=False,
                error=str(e),
            )
    
    async def fill_captcha(
        self,
        input_selector: str,
        text: str,
    ) -> bool:
        """
        填写验证码
        
        Args:
            input_selector: 输入框选择器
            text: 验证码文本
            
        Returns:
            bool: 是否成功
        """
        try:
            await self.page.fill(input_selector, text)
            logger.info(f"验证码已填写: {text}")
            return True
        except Exception as e:
            logger.error(f"填写验证码失败: {e}")
            return False
    
    async def handle_recaptcha_v2(
        self,
        site_key: str,
        action: str = "submit",
    ) -> bool:
        """
        处理reCAPTCHA v2
        
        Args:
            site_key: 站点密钥
            action: 提交动作
            
        Returns:
            bool: 是否成功
        """
        try:
            # 等待reCAPTCHA加载
            await self.page.wait_for_selector('iframe[src*="recaptcha"]', timeout=10000)
            
            # 点击验证复选框
            frame = self.page.frame_locator('iframe[src*="recaptcha"]')
            await frame.locator('#recaptcha-anchor').click()
            
            logger.info("reCAPTCHA v2 已点击")
            
            # 等待验证完成
            await asyncio.sleep(3)
            
            return True
            
        except Exception as e:
            logger.error(f"处理reCAPTCHA失败: {e}")
            return False
    
    async def handle_slider_captcha(
        self,
        slider_selector: str,
        distance: int = 200,
        duration: int = 500,
    ) -> bool:
        """
        处理滑动验证码
        
        Args:
            slider_selector: 滑块选择器
            distance: 滑动距离
            duration: 滑动持续时间（毫秒）
            
        Returns:
            bool: 是否成功
        """
        try:
            slider = self.page.locator(slider_selector)
            box = await slider.bounding_box()
            
            if not box:
                return False
            
            # 获取滑块中心位置
            start_x = box["x"] + box["width"] / 2
            start_y = box["y"] + box["height"] / 2
            
            # 模拟人类滑动
            steps = 20
            for i in range(steps + 1):
                progress = i / steps
                current_x = start_x + distance * progress
                
                # 添加轻微抖动
                jitter = 2 * (0.5 - abs(progress - 0.5))
                current_y = start_y + jitter * (i % 2 * 2 - 1)
                
                await self.page.mouse.move(current_x, current_y)
                await asyncio.sleep(duration / steps / 1000)
            
            logger.info(f"滑动验证码已处理: 距离={distance}px")
            return True
            
        except Exception as e:
            logger.error(f"处理滑动验证码失败: {e}")
            return False
    
    async def detect_captcha_type(self) -> Optional[str]:
        """
        检测页面验证码类型
        
        Returns:
            Optional[str]: 验证码类型
        """
        # 检测reCAPTCHA
        if await self.page.locator('iframe[src*="recaptcha"]').count() > 0:
            return "recaptcha"
        
        # 检测滑动验证码
        if await self.page.locator('[class*="slider"], [class*="drag"]').count() > 0:
            return "slider"
        
        # 检测图片验证码
        if await self.page.locator('img[src*="captcha"]').count() > 0:
            return "image"
        
        # 检测图形验证码
        if await self.page.locator('canvas[id*="captcha"]').count() > 0:
            return "canvas"
        
        # 检测短信验证码输入框
        if await self.page.locator('input[placeholder*="验证码"], input[name*="code"]').count() > 0:
            return "sms"
        
        return None


class SMSHandler:
    """
    短信验证码处理
    提供短信验证码接收辅助
    """
    
    def __init__(self):
        self._sms_services: dict = {}
    
    def add_sms_service(self, name: str, api_url: str, api_key: str):
        """添加短信服务"""
        self._sms_services[name] = {
            "url": api_url,
            "key": api_key,
        }
    
    async def get_sms_code(
        self,
        phone: str,
        service: str = "default",
        timeout: int = 60,
    ) -> Optional[str]:
        """
        获取短信验证码
        
        Args:
            phone: 手机号
            service: 服务名称
            timeout: 超时时间
            
        Returns:
            Optional[str]: 验证码
        """
        logger.info(f"等待短信验证码: {phone}")
        
        # 这里需要实现具体的短信服务API调用
        # 以下为示例代码
        
        import re
        
        start_time = asyncio.get_event_loop().time()
        
        while asyncio.get_event_loop().time() - start_time < timeout:
            try:
                # 模拟获取短信
                # 实际使用时需要调用短信服务API
                await asyncio.sleep(5)
                
                # 模拟收到验证码
                # code = await fetch_sms_from_service(service, phone)
                
            except Exception as e:
                logger.error(f"获取短信验证码失败: {e}")
                await asyncio.sleep(5)
        
        logger.warning(f"获取短信验证码超时: {phone}")
        return None
    
    async def extract_code_from_text(self, text: str) -> Optional[str]:
        """
        从文本中提取验证码
        
        Args:
            text: 短信文本
            
        Returns:
            Optional[str]: 验证码
        """
        import re
        
        # 常见验证码格式
        patterns = [
            r'验证码[：:]\s*(\d{4,6})',
            r'码[：:]\s*(\d{4,6})',
            r'code[：:]\s*(\d{4,6})',
            r'(\d{4,6})',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return match.group(1)
        
        return None
