"""
文件操作模块
支持文件上传、下载、拖拽上传
"""
import asyncio
from typing import Optional, List, Callable
from pathlib import Path
from playwright.async_api import Page, Locator, Download, FileChooser
from loguru import logger
from dataclasses import dataclass
from datetime import datetime


@dataclass
class DownloadResult:
    """下载结果"""
    success: bool
    filename: str
    save_path: str
    size_bytes: int
    duration_ms: float
    error: Optional[str] = None


class FileHandler:
    """文件处理器"""
    
    def __init__(self, page: Page):
        self.page = page
    
    async def upload(self, selector: str, files: List[str], timeout: float = 30) -> bool:
        """上传文件"""
        logger.info(f"上传文件: selector={selector}, files={files}")
        
        locator = self.page.locator(selector)
        
        for f in files:
            if not Path(f).exists():
                logger.error(f"文件不存在: {f}")
                return False
        
        try:
            await locator.set_input_files(files, timeout=timeout * 1000)
            logger.info(f"文件上传成功: {len(files)} 个文件")
            return True
        except Exception as e:
            logger.error(f"文件上传失败: {e}")
            return False
    
    async def download(
        self,
        trigger_selector: str,
        save_dir: str = "./downloads",
        timeout: float = 60,
    ) -> DownloadResult:
        """下载文件"""
        logger.info(f"下载文件: trigger={trigger_selector}")
        
        Path(save_dir).mkdir(parents=True, exist_ok=True)
        start_time = datetime.now()
        
        try:
            async with self.page.expect_download(timeout=timeout * 1000) as download_info:
                await self.page.click(trigger_selector)
            
            download = await download_info.value
            save_path = str(Path(save_dir) / download.suggested_filename)
            await download.save_as(save_path)
            
            file_size = Path(save_path).stat().st_size
            duration = (datetime.now() - start_time).total_seconds() * 1000
            
            logger.info(f"文件下载成功: {save_path}")
            
            return DownloadResult(
                success=True,
                filename=download.suggested_filename,
                save_path=save_path,
                size_bytes=file_size,
                duration_ms=duration,
            )
            
        except Exception as e:
            duration = (datetime.now() - start_time).total_seconds() * 1000
            logger.error(f"文件下载失败: {e}")
            return DownloadResult(
                success=False,
                filename="",
                save_path="",
                size_bytes=0,
                duration_ms=duration,
                error=str(e),
            )
    
    async def screenshot_element(self, selector: str, save_path: str) -> bool:
        """元素截图"""
        try:
            locator = self.page.locator(selector)
            await locator.screenshot(path=save_path)
            logger.info(f"元素截图成功: {save_path}")
            return True
        except Exception as e:
            logger.error(f"元素截图失败: {e}")
            return False
    
    async def pdf(self, save_path: str, format: str = "A4") -> bool:
        """页面保存为PDF"""
        try:
            await self.page.pdf(
                path=save_path,
                format=format,
                print_background=True,
                margin={"top": "1cm", "bottom": "1cm", "left": "1cm", "right": "1cm"},
            )
            logger.info(f"PDF保存成功: {save_path}")
            return True
        except Exception as e:
            logger.error(f"PDF保存失败: {e}")
            return False


class BatchUploader:
    """批量上传器"""
    
    def __init__(self, page: Page):
        self.page = page
        self.file_handler = FileHandler(page)
    
    async def upload_batch(
        self,
        selector: str,
        files: List[str],
        batch_size: int = 5,
        delay: float = 1.0,
    ) -> dict:
        """批量上传文件"""
        results = {"total": len(files), "success": 0, "failed": 0, "errors": []}
        
        for i in range(0, len(files), batch_size):
            batch = files[i:i + batch_size]
            
            for file in batch:
                try:
                    success = await self.file_handler.upload(selector, [file])
                    if success:
                        results["success"] += 1
                    else:
                        results["failed"] += 1
                except Exception as e:
                    results["failed"] += 1
                    results["errors"].append({"file": file, "error": str(e)})
            
            if i + batch_size < len(files):
                await asyncio.sleep(delay)
        
        logger.info(f"批量上传完成: 成功={results['success']}, 失败={results['failed']}")
        return results
