"""
代码生成器
从页面元素自动生成测试代码
"""
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any
from datetime import datetime
from pathlib import Path
from playwright.async_api import Page
from loguru import logger


@dataclass
class CodeGeneratorConfig:
    """代码生成器配置"""
    include_comments: bool = True
    include_assertions: bool = True
    include_waits: bool = True
    use_page_object_model: bool = False
    framework: str = "pytest"
    indent: str = "    "


@dataclass
class GeneratedCode:
    """生成的代码"""
    content: str
    file_name: str
    imports: List[str] = field(default_factory=list)
    functions: List[str] = field(default_factory=list)
    metadata: Dict[str, Any] = field(default_factory=dict)


class CodeGenerator:
    """代码生成器：从页面元素生成测试代码"""

    def __init__(self, page: Page, config: Optional[CodeGeneratorConfig] = None):
        self.page = page
        self.config = config or CodeGeneratorConfig()
        self._indent = self.config.indent

    async def analyze_page(self) -> Dict[str, Any]:
        """分析页面结构"""
        return await self.page.evaluate("""
            () => {
                const result = {
                    url: window.location.href,
                    title: document.title,
                    forms: [],
                    buttons: [],
                    links: [],
                    inputs: [],
                };
                document.querySelectorAll('form').forEach((form, i) => {
                    const inputs = [];
                    form.querySelectorAll('input, select, textarea').forEach(input => {
                        inputs.push({
                            type: input.type || input.tagName.toLowerCase(),
                            name: input.name,
                            id: input.id,
                            placeholder: input.placeholder,
                        });
                    });
                    result.forms.push({ id: form.id || `form:nth-of-type(${i + 1})`, inputs: inputs });
                });
                document.querySelectorAll('button, input[type="submit"], [role="button"]').forEach(btn => {
                    result.buttons.push({
                        text: btn.innerText?.trim() || btn.value,
                        id: btn.id,
                        type: btn.type,
                    });
                });
                document.querySelectorAll('input, textarea').forEach(input => {
                    result.inputs.push({
                        type: input.type || 'text',
                        name: input.name,
                        id: input.id,
                        placeholder: input.placeholder,
                    });
                });
                return result;
            }
        """)

    async def generate_test(
        self,
        test_name: str = "auto_generated_test",
        url: Optional[str] = None,
    ) -> GeneratedCode:
        """生成测试代码"""
        analysis = await self.analyze_page()
        target_url = url or analysis["url"]

        lines = [
            "import asyncio",
            "from playwright_ez import EasyBrowser",
            "",
            "",
        ]

        if self.config.include_comments:
            lines.extend([
                '"""',
                f"自动生成的测试: {test_name}",
                f"URL: {target_url}",
                '"""',
                "",
            ])

        lines.append(f"async def test_{test_name}():")
        lines.append(f'{self._indent}async with EasyBrowser() as browser:')
        lines.append(f'{self._indent}{self._indent}await browser.goto("{target_url}")')

        for i, form in enumerate(analysis.get("forms", [])[:1]):
            for inp in form.get("inputs", [])[:3]:
                selector = f'#{inp["id"]}' if inp.get("id") else f'[name="{inp["name"]}"]'
                if inp.get("type") in ["text", "email", "password"]:
                    sample = "test@example.com" if inp["type"] == "email" else "测试值"
                    lines.append(f'{self._indent}{self._indent}await browser.type_text("{selector}", "{sample}")')

        if analysis.get("buttons"):
            btn = analysis["buttons"][0]
            selector = f'#{btn["id"]}' if btn.get("id") else f'button:has-text("{btn.get("text", "")}")'
            lines.append(f'{self._indent}{self._indent}await browser.click("{selector}")')

        lines.extend([
            "",
            "",
            "if __name__ == '__main__':",
            f'{self._indent}asyncio.run(test_{test_name}())',
        ])

        return GeneratedCode(
            content="\n".join(lines),
            file_name=f"test_{test_name}.py",
            metadata={"url": target_url, "generated_at": datetime.now().isoformat()},
        )

    async def generate_selectors(self) -> Dict[str, str]:
        """生成所有元素的选择器"""
        analysis = await self.analyze_page()
        selectors = {}

        for inp in analysis.get("inputs", []):
            name = inp.get("name") or inp.get("id") or "input"
            selector = f'#{inp["id"]}' if inp.get("id") else f'[name="{inp.get("name", "")}"]'
            selectors[name] = selector

        for btn in analysis.get("buttons", []):
            text = btn.get("text", "").strip()
            if text:
                name = text.lower().replace(" ", "_")[:20]
                selectors[name] = f'#{btn["id"]}' if btn.get("id") else f'button:has-text("{text}")'

        return selectors

    async def save_code(self, code: GeneratedCode, output_dir: str = "./generated") -> str:
        """保存生成的代码"""
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)
        file_path = output_path / code.file_name
        file_path.write_text(code.content, encoding='utf-8')
        logger.info(f"代码已保存: {file_path}")
        return str(file_path)


def create_code_generator(page: Page, config: Optional[CodeGeneratorConfig] = None) -> CodeGenerator:
    """创建代码生成器实例"""
    return CodeGenerator(page, config)
