import random
import asyncio
from typing import Optional

class PasteTypingSimulator:
    """模拟用户复制粘贴行为的输入模拟器"""
    def __init__(self, page=None):
        self.page = page
        self.config = {
            'pre_paste_delay': (0.5, 1.2),    # 粘贴前的停顿时间
            'post_paste_delay': (0.8, 1.5),   # 粘贴后的停顿时间
            'review_probability': 0.7,         # 检查内容的概率
            'review_time': (1.5, 3.0),        # 检查内容的时间
            'adjust_probability': 0.4,         # 调整格式的概率
            'adjust_delay': (0.3, 0.8),       # 调整时的停顿
            'scroll_probability': 0.6,         # 滚动查看的概率
            'scroll_delay': (0.5, 1.0),       # 滚动时的停顿
        }

    async def paste_text(self, selector: str, text: str = None) -> bool:
        """模拟用户粘贴文本的行为
        
        Args:
            selector: 输入框的选择器
            text: 要粘贴的文本，如果不提供则使用剪贴板中的内容
        """
        try:
            # 1. 先等待目标元素并点击以获取焦点
            element = await self.page.wait_for_selector(selector, timeout=5000)
            await element.click()
            await asyncio.sleep(random.uniform(0.2, 0.4))
            
            # 2. 全选当前内容（如果有的话）并删除
            await self.page.keyboard.press("Control+A")
            await asyncio.sleep(random.uniform(0.1, 0.2))
            await self.page.keyboard.press("Delete")
            await asyncio.sleep(random.uniform(0.2, 0.4))
            
            # 3. 如果提供了文本，使用更直接可靠的方法
            if text:
                # 直接使用element.fill方法作为备选方案
                try:
                    await element.fill(text)
                    print("使用fill方法成功填充文本")
                    # 粘贴后的检查动作
                    await self._post_paste_actions()
                    return True
                except Exception as fill_error:
                    print(f"fill方法失败，尝试剪贴板方法: {fill_error}")
                    
                # 如果fill方法失败，尝试剪贴板方法
                # 使用更简单可靠的方式复制文本到剪贴板
                await self.page.evaluate('(text) => {' +
                    'return navigator.clipboard.writeText(text);' +
                '}', text)
                await asyncio.sleep(random.uniform(0.3, 0.5))
            
            # 4. 简化的粘贴操作，直接使用Control+V
            # 确保焦点在元素上
            await element.click()
            await asyncio.sleep(random.uniform(0.1, 0.2))
            
            # 直接执行粘贴
            await self.page.keyboard.press("Control+V")
            await asyncio.sleep(random.uniform(0.4, 0.7))
            
            # 验证文本是否已粘贴
            try:
                current_text = await element.input_value()
                if not current_text or (text and text not in current_text):
                    print(f"警告: 粘贴可能失败。当前文本长度: {len(current_text)}")
                    # 最后的备选方案：直接设置value
                    await element.evaluate(f'(element) => {{ element.value = "{text}"; }}', element)
                    await asyncio.sleep(0.2)
            except Exception as verify_error:
                print(f"验证粘贴时出错: {verify_error}")
            
            # 粘贴后的检查动作
            await self._post_paste_actions()
            
            return True
            
        except Exception as e:
            print(f"粘贴文本时出错: {e}")
            return False

    async def _copy_to_clipboard(self, text: str):
        """将文本可靠地复制到剪贴板
        
        这个方法使用多种方式尝试复制文本，确保文本能正确复制到剪贴板
        """
        try:
            # 方式1：使用更安全的JavaScript，避免模板字符串中的转义问题
            await self.page.evaluate('(text) => {' +
                'const textarea = document.createElement("textarea");' +
                'textarea.style.position = "fixed";' +
                'textarea.style.left = "-999999px";' +
                'textarea.style.top = "-999999px";' +
                'textarea.value = text;' +
                'document.body.appendChild(textarea);' +
                'textarea.focus();' +
                'textarea.select();' +
                'try {' +
                    'document.execCommand("copy");' +
                '} catch (err) {' +
                    'console.error("复制失败:", err);' +
                '}' +
                'document.body.removeChild(textarea);' +
            '}', text)
        except Exception as e:
            print(f"主要复制方法失败: {e}")
            # 方式2：备用方法 - 尝试使用navigator.clipboard API
            try:
                await self.page.evaluate('(text) => navigator.clipboard.writeText(text)', text)
            except Exception as e2:
                print(f"备用复制方法也失败: {e2}")
                # 方式3：最基本的方法 - 直接设置文本区域的值
                await self.page.evaluate('(text) => {' +
                    'const textarea = document.createElement("textarea");' +
                    'textarea.value = text;' +
                    'document.body.appendChild(textarea);' +
                    'textarea.select();' +
                    'document.body.removeChild(textarea);' +
                '}', text)
    
    async def _prepare_input(self, selector: str):
        """准备输入区域"""
        try:
            # 等待元素出现并点击
            element = await self.page.wait_for_selector(selector, timeout=5000)
            await element.click()
            
            # 模拟点击后的短暂停顿
            await asyncio.sleep(random.uniform(0.3, 0.6))
            
            # 清空现有内容
            await self.page.keyboard.press("Control+A")
            await asyncio.sleep(random.uniform(0.1, 0.2))
            await self.page.keyboard.press("Delete")
            await asyncio.sleep(random.uniform(0.2, 0.4))
            
        except Exception as e:
            print(f"准备输入区域失败: {e}")
            raise

    async def _pre_paste_actions(self):
        """模拟粘贴前的准备动作"""
        # 模拟思考和准备时间
        await asyncio.sleep(random.uniform(*self.config['pre_paste_delay']))
        
        # 模拟按下 Ctrl 键，更真实的用户操作
        await self.page.keyboard.down("Control")
        await asyncio.sleep(random.uniform(0.1, 0.2))  # 增加延迟，更接近真实用户

    async def _perform_paste(self):
        """执行粘贴操作，分离按键按下和释放，更接近真实用户行为"""
        # 模拟按下 V 键
        await self.page.keyboard.press("v")
        await asyncio.sleep(random.uniform(0.1, 0.2))
        
        # 释放 Ctrl 键
        await self.page.keyboard.up("Control")
        
        # 等待内容出现，给足够的时间让内容粘贴完成
        await asyncio.sleep(random.uniform(0.4, 0.7))
        
        # 验证粘贴是否成功（可选）
        try:
            # 可以添加验证逻辑来确认内容是否已粘贴
            pass
        except Exception:
            # 即使验证失败也不中断流程
            pass

    async def _post_paste_actions(self):
        """模拟粘贴后的检查和调整动作"""
        # 随机检查内容
        if random.random() < self.config['review_probability']:
            # 模拟鼠标滚动查看内容
            if random.random() < self.config['scroll_probability']:
                # 向下滚动一点
                await self.page.mouse.wheel(0, 100)
                await asyncio.sleep(random.uniform(0.3, 0.6))
                # 停顿一下，像是在阅读
                await asyncio.sleep(random.uniform(0.5, 1.0))
                # 再滚动回来
                await self.page.mouse.wheel(0, -100)
                await asyncio.sleep(random.uniform(0.3, 0.6))
            
            # 随机点击文本框内部的某个位置（模拟检查或准备编辑）
            if random.random() < 0.3:  # 30%的概率
                element = await self.page.query_selector('textarea')
                if element:
                    box = await element.bounding_box()
                    if box:
                        x = box['x'] + random.uniform(10, box['width'] - 10)
                        y = box['y'] + random.uniform(10, box['height'] - 10)
                        await self.page.mouse.click(x, y)
                        await asyncio.sleep(random.uniform(0.2, 0.5))
            
            # 随机调整格式
            if random.random() < self.config['adjust_probability']:
                # 模拟删除多余空行
                for _ in range(random.randint(1, 2)):
                    await self.page.keyboard.press("End")
                    await asyncio.sleep(random.uniform(0.1, 0.2))
                    await self.page.keyboard.press("Backspace")
                    await asyncio.sleep(random.uniform(*self.config['adjust_delay']))

    async def paste_with_format_check(self, text: str, selector: str = None) -> bool:
        """带格式检查的粘贴方法"""
        try:
            if selector:
                # 如果提供了选择器，先准备输入区域
                element = await self.page.wait_for_selector(selector, timeout=5000)
                await element.click()
                await asyncio.sleep(random.uniform(0.2, 0.4))
                
                # 清空现有内容
                await self.page.keyboard.press("Control+A")
                await asyncio.sleep(random.uniform(0.1, 0.2))
                await self.page.keyboard.press("Delete")
                await asyncio.sleep(random.uniform(0.2, 0.4))
            
            # 可靠地复制文本到剪贴板
            await self._copy_to_clipboard(text)
            await asyncio.sleep(random.uniform(*self.config['pre_paste_delay']))
            
            # 模拟真实的粘贴操作
            await self._pre_paste_actions()
            await self._perform_paste()
            
            # 模拟粘贴后的检查
            await asyncio.sleep(random.uniform(*self.config['post_paste_delay']))
            
            # 随机检查内容
            if random.random() < self.config['review_probability']:
                await asyncio.sleep(random.uniform(*self.config['review_time']))
            
            return True
            
        except Exception as e:
            print(f"格式检查粘贴失败: {e}")
            return False
