"""
爬虫模板
预定义常见网站的爬虫模板
"""
import json
from typing import Optional, Dict, Any, List
from playwright.async_api import Page

from .basic import DataExtractor


class ScraperTemplate:
    """
    爬虫模板
    预定义常见网站的爬虫模板
    """

    def __init__(self, page: Page):
        self.extractor = DataExtractor(page)
        self.page = page

    async def scrape_product(
        self,
        selectors: Optional[Dict[str, str]] = None,
    ) -> Dict[str, Any]:
        """
        抓取电商产品页面

        Args:
            selectors: 自定义选择器

        Returns:
            Dict: 产品信息
        """
        default_selectors = {
            "title": "h1",
            "price": ".price",
            "original_price": ".original-price",
            "description": ".description",
            "images": "img.product-image",
            "rating": ".rating",
            "reviews_count": ".reviews-count",
        }

        selectors = {**default_selectors, **(selectors or {})}

        data = {}

        # 标题
        data["title"] = await self.extractor.extract_text(selectors["title"])

        # 价格
        price_text = await self.extractor.extract_text(selectors["price"])
        if price_text:
            data["price"] = self.extractor._transforms["price"](price_text)

        # 原价
        orig_price = await self.extractor.extract_text(selectors["original_price"])
        if orig_price:
            data["original_price"] = self.extractor._transforms["price"](orig_price)

        # 描述
        data["description"] = await self.extractor.extract_text(selectors["description"])

        # 图片
        data["images"] = await self.extractor.extract_attributes(selectors["images"], "src")

        # URL
        data["url"] = self.page.url

        return data

    async def scrape_article(
        self,
        selectors: Optional[Dict[str, str]] = None,
    ) -> Dict[str, Any]:
        """
        抓取文章页面

        Args:
            selectors: 自定义选择器

        Returns:
            Dict: 文章信息
        """
        default_selectors = {
            "title": "h1",
            "author": ".author",
            "date": ".date, time",
            "content": "article, .content, .post-content",
            "tags": ".tags a, .tag",
        }

        selectors = {**default_selectors, **(selectors or {})}

        data = {}

        data["title"] = await self.extractor.extract_text(selectors["title"])
        data["author"] = await self.extractor.extract_text(selectors["author"])
        data["date"] = await self.extractor.extract_text(selectors["date"])
        data["content"] = await self.extractor.extract_text(selectors["content"])
        data["tags"] = await self.extractor.extract_texts(selectors["tags"])
        data["url"] = self.page.url

        return data

    async def scrape_search_results(
        self,
        result_selector: str,
        title_selector: str,
        link_selector: str,
        description_selector: Optional[str] = None,
    ) -> List[Dict[str, str]]:
        """
        抓取搜索结果 - 批量优化版

        Args:
            result_selector: 结果项选择器
            title_selector: 标题选择器
            link_selector: 链接选择器
            description_selector: 描述选择器

        Returns:
            List[Dict]: 搜索结果列表
        """
        try:
            has_desc = "true" if description_selector else "false"
            desc_selector = description_selector or ""

            results = await self.page.evaluate(f"""
                () => {{
                    const results = [];
                    const items = document.querySelectorAll('{result_selector}');

                    items.forEach(item => {{
                        const titleEl = item.querySelector('{title_selector}');
                        const linkEl = item.querySelector('{link_selector}');

                        const result = {{
                            title: titleEl ? titleEl.textContent.trim() : '',
                            link: linkEl ? linkEl.href : '',
                        }};

                        if ({has_desc}) {{
                            const descEl = item.querySelector('{desc_selector}');
                            result.description = descEl ? descEl.textContent.trim() : '';
                        }}

                        results.push(result);
                    }});

                    return results;
                }}
            """)
            return results
        except:
            return []

    async def scrape_listing(
        self,
        item_selector: str,
        fields: Dict[str, str],
        max_items: int = 0,
    ) -> List[Dict[str, Any]]:
        """
        抓取列表页面 - 批量优化版

        Args:
            item_selector: 列表项选择器
            fields: 字段映射 {字段名: 选择器}
            max_items: 最大抓取数量 (0表示全部)

        Returns:
            List[Dict]: 列表数据
        """
        try:
            fields_json = json.dumps(fields)
            limit_clause = f".slice(0, {max_items})" if max_items > 0 else ""

            results = await self.page.evaluate(f"""
                () => {{
                    const items = document.querySelectorAll('{item_selector}');
                    const fields = {fields_json};
                    const results = [];

                    items.forEach(item => {{
                        const row = {{}};
                        for (const [fieldName, fieldSelector] of Object.entries(fields)) {{
                            try {{
                                const el = item.querySelector(fieldSelector);
                                row[fieldName] = el ? el.textContent.trim() : null;
                            }} catch {{
                                row[fieldName] = null;
                            }}
                        }}
                        results.push(row);
                    }});

                    return results{limit_clause};
                }}
            """)
            return results
        except:
            return []
