"""
浏览器扩展支持
支持Chrome扩展的加载和管理
"""
import json
from typing import Optional, List, Dict, Any
from pathlib import Path
from playwright.async_api import BrowserContext
from loguru import logger


class ExtensionManager:
    """
    浏览器扩展管理器
    支持加载、启用、禁用Chrome扩展
    """
    
    def __init__(self, context: BrowserContext):
        self.context = context
        self._extensions: Dict[str, Dict] = {}
    
    async def load_from_path(self, extension_path: str) -> Optional[str]:
        """
        从路径加载扩展
        
        Args:
            extension_path: 扩展目录路径
            
        Returns:
            Optional[str]: 扩展ID
        """
        path = Path(extension_path)
        
        if not path.exists():
            logger.error(f"扩展路径不存在: {extension_path}")
            return None
        
        # 检查manifest.json
        manifest_path = path / "manifest.json"
        if not manifest_path.exists():
            logger.error(f"缺少manifest.json: {extension_path}")
            return None
        
        with open(manifest_path, 'r', encoding='utf-8') as f:
            manifest = json.load(f)
        
        extension_id = self._generate_extension_id(path)
        
        self._extensions[extension_id] = {
            "path": extension_path,
            "name": manifest.get("name", "Unknown"),
            "version": manifest.get("version", "1.0"),
            "manifest": manifest,
        }
        
        logger.info(f"加载扩展: {manifest.get('name')} ({extension_id})")
        return extension_id
    
    def _generate_extension_id(self, path: Path) -> str:
        """生成扩展ID"""
        import hashlib
        return hashlib.md5(str(path).encode()).hexdigest()[:32]
    
    async def load_from_crx(self, crx_path: str) -> Optional[str]:
        """
        从.crx文件加载扩展
        
        Args:
            crx_path: .crx文件路径
            
        Returns:
            Optional[str]: 扩展ID
        """
        # 解压crx文件
        import zipfile
        import tempfile
        
        crx_file = Path(crx_path)
        if not crx_file.exists():
            logger.error(f"CRX文件不存在: {crx_path}")
            return None
        
        # 创建临时目录解压
        temp_dir = Path(tempfile.mkdtemp())
        
        try:
            # CRX文件实际上是特殊格式的ZIP
            with zipfile.ZipFile(crx_file, 'r') as zf:
                zf.extractall(temp_dir)
            
            return await self.load_from_path(str(temp_dir))
            
        except Exception as e:
            logger.error(f"解压CRX文件失败: {e}")
            return None
    
    def list_extensions(self) -> List[Dict[str, Any]]:
        """列出所有已加载扩展"""
        return [
            {
                "id": ext_id,
                "name": ext["name"],
                "version": ext["version"],
                "path": ext["path"],
            }
            for ext_id, ext in self._extensions.items()
        ]
    
    def get_extension(self, extension_id: str) -> Optional[Dict]:
        """获取扩展信息"""
        return self._extensions.get(extension_id)
    
    def remove_extension(self, extension_id: str):
        """移除扩展"""
        if extension_id in self._extensions:
            del self._extensions[extension_id]
            logger.info(f"移除扩展: {extension_id}")


class AdBlocker:
    """
    广告拦截器
    拦截常见广告和追踪器
    """
    
    # 常见广告域名
    AD_DOMAINS = [
        "doubleclick.net",
        "googlesyndication.com",
        "googleadservices.com",
        "facebook.com/tr",
        "analytics.google.com",
        "google-analytics.com",
        "adservice.google.com",
        "ad.doubleclick.net",
        "pagead2.googlesyndication.com",
        "ads.twitter.com",
        "ads.linkedin.com",
    ]
    
    # 追踪器域名
    TRACKER_DOMAINS = [
        "facebook.net",
        "connect.facebook.net",
        "platform.twitter.com",
        "staticxx.facebook.com",
        "analytics.twitter.com",
        "pixel.facebook.com",
    ]
    
    def __init__(self, page):
        self.page = page
        self._blocked_count = 0
    
    async def enable(self):
        """启用广告拦截"""
        all_domains = self.AD_DOMAINS + self.TRACKER_DOMAINS
        
        async def block_ads(route):
            url = route.request.url
            
            for domain in all_domains:
                if domain in url:
                    self._blocked_count += 1
                    logger.debug(f"拦截广告/追踪器: {url}")
                    await route.abort()
                    return
            
            await route.continue_()
        
        await self.page.route("**/*", block_ads)
        logger.info("广告拦截已启用")
    
    async def disable(self):
        """禁用广告拦截"""
        await self.page.unroute("**/*")
        logger.info("广告拦截已禁用")
    
    def get_blocked_count(self) -> int:
        """获取拦截数量"""
        return self._blocked_count


class PrivacyProtector:
    """
    隐私保护器
    保护用户隐私，防止追踪
    """
    
    def __init__(self, page):
        self.page = page
    
    async def block_webrtc(self):
        """阻止WebRTC泄露"""
        await self.page.add_init_script("""
            // 阻止WebRTC泄露真实IP
            const RTC = window.RTCPeerConnection || window.webkitRTCPeerConnection;
            if (RTC) {
                window.RTCPeerConnection = function(...args) {
                    return new RTC(...args);
                };
                window.RTCPeerConnection.prototype = RTC.prototype;
            }
        """)
        logger.info("WebRTC泄露保护已启用")
    
    async def block_canvas_fingerprint(self):
        """阻止Canvas指纹"""
        await self.page.add_init_script("""
            // 添加噪声到Canvas指纹
            const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
            HTMLCanvasElement.prototype.toDataURL = function(type) {
                if (type === 'image/png' && this.width === 280 && this.height === 60) {
                    // 可能是指纹检测
                    const context = this.getContext('2d');
                    const imageData = context.getImageData(0, 0, this.width, this.height);
                    for (let i = 0; i < imageData.data.length; i += 4) {
                        imageData.data[i] ^= (Math.random() * 2) | 0;
                    }
                    context.putImageData(imageData, 0, 0);
                }
                return originalToDataURL.apply(this, arguments);
            };
        """)
        logger.info("Canvas指纹保护已启用")
    
    async def block_audio_fingerprint(self):
        """阻止音频指纹"""
        await self.page.add_init_script("""
            // 添加噪声到音频指纹
            const audioContext = window.AudioContext || window.webkitAudioContext;
            if (audioContext) {
                const originalCreateAnalyser = audioContext.prototype.createAnalyser;
                audioContext.prototype.createAnalyser = function() {
                    const analyser = originalCreateAnalyser.apply(this, arguments);
                    const originalGetFloatFrequencyData = analyser.getFloatFrequencyData;
                    analyser.getFloatFrequencyData = function(array) {
                        originalGetFloatFrequencyData.apply(this, arguments);
                        for (let i = 0; i < array.length; i++) {
                            array[i] += (Math.random() - 0.5) * 0.1;
                        }
                    };
                    return analyser;
                };
            }
        """)
        logger.info("音频指纹保护已启用")
    
    async def enable_all_protection(self):
        """启用所有隐私保护"""
        await self.block_webrtc()
        await self.block_canvas_fingerprint()
        await self.block_audio_fingerprint()
        logger.info("所有隐私保护已启用")
    
    async def clear_storage(self):
        """清除所有存储"""
        await self.page.evaluate("""
            () => {
                localStorage.clear();
                sessionStorage.clear();
                document.cookie.split(';').forEach(c => {
                    document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
                });
            }
        """)
        logger.info("存储已清除")
    
    async def clear_cache(self):
        """清除缓存"""
        cdp = await self.page.context.new_cdp_session(self.page)
        await cdp.send('Network.clearBrowserCache')
        logger.info("缓存已清除")


class CookieConsentHandler:
    """
    Cookie同意处理
    自动处理Cookie同意弹窗
    """
    
    def __init__(self, page):
        self.page = page
    
    async def auto_accept(self):
        """自动接受Cookie同意"""
        accept_selectors = [
            # 通用选择器
            "button[id*='accept']",
            "button[id*='cookie']",
            "button[class*='accept']",
            "a[class*='accept']",
            "[data-testid*='accept']",
            "[data-testid*='cookie']",
            
            # 常见CMP
            "#onetrust-accept-btn-handler",
            ".cc-accept",
            ".cc-dismiss",
            "#ccc-notify-accept",
            "#cookie-banner-accept",
            "[aria-label*='Accept']",
            "[aria-label*='accept']",
            "[aria-label*='Akkoord']",  # 荷兰语
            "[aria-label*='Aceptar']",  # 西班牙语
            "[aria-label*='Accepter']", # 法语
            
            # 特定平台
            "button[data-testid*='cookie-banner-accept']",
            "button[data-cy*='accept-cookies']",
        ]
        
        for selector in accept_selectors:
            try:
                element = self.page.locator(selector)
                if await element.count() > 0:
                    await element.first.click(timeout=1000)
                    logger.info(f"已接受Cookie同意: {selector}")
                    return True
            except:
                continue
        
        logger.info("未找到Cookie同意弹窗")
        return False
    
    async def auto_reject(self):
        """自动拒绝Cookie同意"""
        reject_selectors = [
            "button[id*='reject']",
            "button[class*='reject']",
            "button[data-testid*='reject']",
            "[aria-label*='Reject']",
            "[aria-label*='拒绝']",
            "a[class*='reject']",
            ".cc-reject",
            "#ccc-notify-reject",
        ]
        
        for selector in reject_selectors:
            try:
                element = self.page.locator(selector)
                if await element.count() > 0:
                    await element.first.click(timeout=1000)
                    logger.info(f"已拒绝Cookie同意: {selector}")
                    return True
            except:
                continue
        
        # 如果找不到拒绝按钮，尝试接受
        return await self.auto_accept()