import time
import random
from playwright.sync_api import Page
from playwright.async_api import Page as AsyncPage
from .human_like import HumanLikeTyper
import asyncio
from typing import Union, Optional, List, Dict, Any


class HumanTypingWrapper:
    """
    人类化输入包装器，提供更高级的人类化输入功能
    支持同步和异步页面操作
    """
    
    def __init__(self, page: Union[Page, AsyncPage], config: Optional[Dict[str, Any]] = None):
        self.page = page
        self.is_async = hasattr(page, 'wait_for_timeout')  # 检测是否为异步页面
        
        # 初始化配置
        self.config = self._init_config(config)
        
        # 初始化human_like模块（仅用于同步页面）
        if not self.is_async:
            self.human_typer = HumanLikeTyper(page)
        
    def _init_config(self, config: Optional[Dict[str, Any]]) -> Dict[str, Any]:
        """初始化配置参数"""
        default_config = {
            # 输入速度设置（字符/秒）
            'min_typing_speed': 2,
            'max_typing_speed': 10,
            
            # 思考停顿设置
            'pause_probability': 0.15,  # 15%的概率停顿
            'min_pause_duration': 0.3,
            'max_pause_duration': 2.5,
            
            # 错误修正设置
            'correction_probability': 0.0,  # 禁用错误修正，确保文字准确性
            'backspace_probability': 0.0,  # 禁用退格重输，确保文字准确性
            
            # 点击前后停顿
            'click_delay_before': (0.1, 0.4),
            'click_delay_after': (0.2, 0.6),
            
            # 输入完成后停顿
            'finish_pause_probability': 0.4,  # 40%的概率在输入完成后停顿
            'finish_pause_duration': (0.3, 1.2),
            
            # 分段输入设置（长文本分段输入）
            'chunk_input': True,
            'max_chunk_length': 50,
            'chunk_pause_duration': (0.5, 1.5),
            
            # 模拟疲劳效果
            'fatigue_effect': True,
            'fatigue_threshold': 100,  # 输入超过100个字符后开始疲劳
            'fatigue_slowdown': 0.3,  # 疲劳后速度减慢30%
        }
        
        if config:
            default_config.update(config)
        
        return default_config
    
    def _calculate_typing_delay(self, char_index: int = 0) -> float:
        """计算每个字符之间的延迟时间，考虑疲劳效果"""
        base_speed = random.uniform(
            self.config['min_typing_speed'], 
            self.config['max_typing_speed']
        )
        
        # 计算疲劳效果
        if (self.config['fatigue_effect'] and 
            char_index > self.config['fatigue_threshold']):
            fatigue_factor = 1 + self.config['fatigue_slowdown']
            base_speed /= fatigue_factor
        
        delay = 1 / base_speed + random.uniform(-0.05, 0.15)
        return max(0.01, delay)  # 确保延迟不为负数
    
    def _should_pause(self) -> bool:
        """判断是否应该停顿思考"""
        return random.random() < self.config['pause_probability']
    
    def _should_correct(self) -> bool:
        """判断是否应该进行错误修正"""
        return random.random() < self.config['correction_probability']
    
    def _should_backspace(self) -> bool:
        """判断是否应该退格重新输入"""
        return random.random() < self.config['backspace_probability']
    
    def _get_random_pause_duration(self) -> float:
        """获取随机停顿时长"""
        return random.uniform(
            self.config['min_pause_duration'],
            self.config['max_pause_duration']
        )
    
    def _get_wrong_char(self, correct_char: str) -> str:
        """生成错误字符"""
        # 键盘相邻字符映射
        keyboard_neighbors = {
            'a': 'sqw', 'b': 'vghn', 'c': 'xdfv', 'd': 'erfcxs', 'e': 'wsdr',
            'f': 'rtgvcd', 'g': 'tyhbvf', 'h': 'yujnbg', 'i': 'ujko', 'j': 'uikmnh',
            'k': 'iolmj', 'l': 'opmk', 'm': 'njk', 'n': 'bhjm', 'o': 'iklp',
            'p': 'ol', 'q': 'wa', 'r': 'edft', 's': 'awedxz', 't': 'rfgy',
            'u': 'yhij', 'v': 'cfgb', 'w': 'qase', 'x': 'zsdc', 'y': 'tghu',
            'z': 'asx'
        }
        
        char_lower = correct_char.lower()
        if char_lower in keyboard_neighbors:
            neighbors = keyboard_neighbors[char_lower]
            wrong_char = random.choice(neighbors)
            # 保持原始大小写
            return wrong_char.upper() if correct_char.isupper() else wrong_char
        else:
            # 如果不在映射中，返回随机字符
            return random.choice('abcdefghijklmnopqrstuvwxyz')
    
    async def _sleep(self, duration: float):
        """统一的睡眠方法，兼容同步和异步"""
        if self.is_async:
            await asyncio.sleep(duration)
        else:
            time.sleep(duration)
    
    async def _type_char(self, char: str, delay: float):
        """输入单个字符，兼容同步和异步"""
        if self.is_async:
            await self.page.keyboard.type(char, delay=delay * 1000)
        else:
            self.page.keyboard.type(char, delay=delay * 1000)
    
    async def _press_key(self, key: str):
        """按键操作，兼容同步和异步"""
        if self.is_async:
            await self.page.keyboard.press(key)
        else:
            self.page.keyboard.press(key)
    
    async def _click_element(self, selector: str):
        """点击元素，兼容同步和异步"""
        if self.is_async:
            await self.page.click(selector)
        else:
            self.page.click(selector)
    
    async def _wait_for_selector(self, selector: str, timeout: int = 30000):
        """等待选择器，兼容同步和异步"""
        if self.is_async:
            await self.page.wait_for_selector(selector, timeout=timeout)
        else:
            self.page.wait_for_selector(selector, timeout=timeout)
    
    async def type_text_human(self, selector: str, text: str, clear_first: bool = True) -> bool:
        """
        以人类化方式在指定元素中输入文本
        
        Args:
            selector: 元素选择器
            text: 要输入的文本
            clear_first: 是否先清空现有内容
            
        Returns:
            bool: 是否成功输入
        """
        try:
            # 等待元素并点击
            await self._wait_for_selector(selector)
            
            # 点击前停顿
            delay_before = random.uniform(*self.config['click_delay_before'])
            await self._sleep(delay_before)
            
            # 点击元素
            await self._click_element(selector)
            
            # 点击后停顿
            delay_after = random.uniform(*self.config['click_delay_after'])
            await self._sleep(delay_after)
            
            # 清空现有内容
            if clear_first:
                await self._press_key("Control+A")
                await self._sleep(0.1)
                await self._press_key("Delete")
                await self._sleep(0.2)
            
            # 分段输入长文本
            if self.config['chunk_input'] and len(text) > self.config['max_chunk_length']:
                await self._type_text_in_chunks(text)
            else:
                await self._type_text_continuously(text)
            
            # 输入完成后可能停顿
            if random.random() < self.config['finish_pause_probability']:
                pause_duration = random.uniform(*self.config['finish_pause_duration'])
                await self._sleep(pause_duration)
            
            return True
            
        except Exception as e:
            print(f"人类化输入失败: {e}")
            return False
    
    async def _type_text_continuously(self, text: str):
        """连续输入文本，包含人类化效果"""
        current_input = ""
        
        for i, char in enumerate(text):
            # 随机停顿思考
            if self._should_pause():
                pause_duration = self._get_random_pause_duration()
                await self._sleep(pause_duration)
            
            # 随机错误修正
            if current_input and self._should_correct():
                await self._simulate_correction(char)
            
            # 随机退格重新输入
            if current_input and self._should_backspace():
                await self._simulate_backspace_retype(char)
            
            # 计算延迟并输入字符
            delay = self._calculate_typing_delay(i)
            await self._type_char(char, delay)
            
            current_input += char
            
            # 字符间微小停顿
            micro_pause = random.uniform(0.01, 0.08)
            await self._sleep(micro_pause)
    
    async def _type_text_in_chunks(self, text: str):
        """分段输入长文本"""
        chunk_size = self.config['max_chunk_length']
        chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
        
        for i, chunk in enumerate(chunks):
            await self._type_text_continuously(chunk)
            
            # 段落间停顿（除了最后一段）
            if i < len(chunks) - 1:
                pause_duration = random.uniform(*self.config['chunk_pause_duration'])
                await self._sleep(pause_duration)
    
    async def _simulate_correction(self, next_char: str):
        """模拟输入错误并修正"""
        # 删除最后一个字符
        await self._press_key("Backspace")
        await self._sleep(random.uniform(0.1, 0.4))
        
        # 输入错误字符
        wrong_char = self._get_wrong_char(next_char)
        delay = self._calculate_typing_delay()
        await self._type_char(wrong_char, delay)
        await self._sleep(random.uniform(0.2, 0.5))
        
        # 删除错误字符
        await self._press_key("Backspace")
        await self._sleep(random.uniform(0.1, 0.3))
    
    async def _simulate_backspace_retype(self, target_char: str):
        """模拟退格后重新输入"""
        backspace_count = random.randint(1, min(3, len(target_char)))
        
        # 执行退格
        for _ in range(backspace_count):
            await self._press_key("Backspace")
            await self._sleep(random.uniform(0.1, 0.2))
        
        # 短暂停顿
        await self._sleep(random.uniform(0.2, 0.6))
    
    async def click_and_type(self, selector: str, text: str, **kwargs) -> bool:
        """
        点击元素并输入文本的便捷方法
        
        Args:
            selector: 元素选择器
            text: 要输入的文本
            **kwargs: 传递给type_text_human的额外参数
            
        Returns:
            bool: 是否成功
        """
        return await self.type_text_human(selector, text, **kwargs)
    
    async def human_click(self, selector: str, wait_after: bool = True) -> bool:
        """
        人类化点击元素
        
        Args:
            selector: 元素选择器
            wait_after: 点击后是否等待
            
        Returns:
            bool: 是否成功点击
        """
        try:
            await self._wait_for_selector(selector)
            
            # 点击前停顿
            delay_before = random.uniform(*self.config['click_delay_before'])
            await self._sleep(delay_before)
            
            # 点击
            await self._click_element(selector)
            
            # 点击后停顿
            if wait_after:
                delay_after = random.uniform(*self.config['click_delay_after'])
                await self._sleep(delay_after)
            
            return True
            
        except Exception as e:
            print(f"人类化点击失败: {e}")
            return False
    
    async def human_scroll(self, direction: str = "down", amount: int = 3):
        """
        人类化滚动页面
        
        Args:
            direction: 滚动方向 "up" 或 "down"
            amount: 滚动次数
        """
        key = "PageDown" if direction == "down" else "PageUp"
        
        for i in range(amount):
            await self._press_key(key)
            # 滚动间隔
            pause = random.uniform(0.3, 0.8)
            await self._sleep(pause)
    
    def update_config(self, new_config: Dict[str, Any]):
        """更新配置"""
        self.config.update(new_config)
    
    def get_config(self) -> Dict[str, Any]:
        """获取当前配置"""
        return self.config.copy()


# 便捷的工厂函数
def create_human_typer(page: Union[Page, AsyncPage], config: Optional[Dict[str, Any]] = None) -> HumanTypingWrapper:
    """
    创建人类化输入包装器的工厂函数
    
    Args:
        page: Playwright页面对象（同步或异步）
        config: 可选的配置字典
        
    Returns:
        HumanTypingWrapper实例
    """
    return HumanTypingWrapper(page, config)
