"""
SEO 检查器
SEO 基础检查，Meta 标签、标题、结构化数据验证
"""
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any, Callable
from playwright.async_api import Page
from loguru import logger


@dataclass
class SEOCheckResult:
    """SEO 检查结果"""
    id: str
    name: str
    passed: bool
    score: float
    description: str
    details: List[str] = field(default_factory=list)


@dataclass
class SEOReport:
    """SEO 报告"""
    url: str
    total_score: float
    checks: List[SEOCheckResult]
    passed_count: int
    failed_count: int


class SEOChecker:
    """
    SEO 检查器
    检查页面的 SEO 相关指标
    """

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

    async def check(self) -> SEOReport:
        """
        执行 SEO 检查

        Returns:
            SEOReport: 检查报告
        """
        url = self.page.url

        # 执行各项检查
        checks = [
            await self._check_title(),
            await self._check_meta_description(),
            await self._check_h1(),
            await self._check_images_alt(),
            await self._check_canonical(),
            await self._check_viewport(),
            await self._check_robots(),
            await self._check_og_tags(),
            await self._check_structured_data(),
            await self._check_links(),
        ]

        # 计算总分
        total_score = sum(c.score for c in checks) / len(checks) if checks else 0
        passed_count = sum(1 for c in checks if c.passed)
        failed_count = len(checks) - passed_count

        logger.debug(f"SEO 检查完成: score={total_score:.1f}, passed={passed_count}/{len(checks)}")

        return SEOReport(
            url=url,
            total_score=total_score,
            checks=checks,
            passed_count=passed_count,
            failed_count=failed_count,
        )

    async def _check_title(self) -> SEOCheckResult:
        """检查页面标题"""
        title = await self.page.title()
        length = len(title)
        passed = 10 <= length <= 60

        if length == 0:
            description = "缺少页面标题"
            score = 0
        elif length < 10:
            description = f"标题过短 ({length} 字符)，建议 10-60 字符"
            score = 50
        elif length > 60:
            description = f"标题过长 ({length} 字符)，建议 10-60 字符"
            score = 50
        else:
            description = f"标题长度适中 ({length} 字符)"
            score = 100

        return SEOCheckResult(
            id="title",
            name="页面标题",
            passed=passed,
            score=score,
            description=description,
            details=[title] if title else [],
        )

    async def _check_meta_description(self) -> SEOCheckResult:
        """检查 Meta Description"""
        description_el = self.page.locator('meta[name="description"]')
        content = await description_el.get_attribute("content")
        length = len(content) if content else 0
        passed = 50 <= length <= 160

        if length == 0:
            description = "缺少 Meta Description"
            score = 0
        elif length < 50:
            description = f"Meta Description 过短 ({length} 字符)，建议 50-160 字符"
            score = 50
        elif length > 160:
            description = f"Meta Description 过长 ({length} 字符)，建议 50-160 字符"
            score = 50
        else:
            description = f"Meta Description 长度适中 ({length} 字符)"
            score = 100

        return SEOCheckResult(
            id="meta-description",
            name="Meta Description",
            passed=passed,
            score=score,
            description=description,
            details=[content[:100]] if content else [],
        )

    async def _check_h1(self) -> SEOCheckResult:
        """检查 H1 标题"""
        h1_count = await self.page.locator("h1").count()
        passed = h1_count == 1

        if h1_count == 0:
            description = "缺少 H1 标题"
            score = 0
        elif h1_count == 1:
            description = "存在唯一的 H1 标题"
            score = 100
        else:
            description = f"存在 {h1_count} 个 H1 标题，建议只保留一个"
            score = 50

        return SEOCheckResult(
            id="h1",
            name="H1 标题",
            passed=passed,
            score=score,
            description=description,
        )

    async def _check_images_alt(self) -> SEOCheckResult:
        """检查图片 Alt 属性"""
        images = self.page.locator("img")
        total = await images.count()

        if total == 0:
            return SEOCheckResult(
                id="images-alt",
                name="图片 Alt 属性",
                passed=True,
                score=100,
                description="页面没有图片",
            )

        with_alt = 0
        for i in range(total):
            alt = await images.nth(i).get_attribute("alt")
            if alt is not None:
                with_alt += 1

        score = (with_alt / total) * 100
        passed = with_alt == total

        return SEOCheckResult(
            id="images-alt",
            name="图片 Alt 属性",
            passed=passed,
            score=score,
            description=f"{with_alt}/{total} 张图片有 Alt 属性",
            details=[f"{total - with_alt} 张图片缺少 Alt 属性"] if not passed else [],
        )

    async def _check_canonical(self) -> SEOCheckResult:
        """检查 Canonical URL"""
        canonical = await self.page.locator('link[rel="canonical"]').get_attribute("href")
        passed = bool(canonical)

        return SEOCheckResult(
            id="canonical",
            name="Canonical URL",
            passed=passed,
            score=100 if passed else 0,
            description="存在 Canonical URL" if passed else "缺少 Canonical URL",
            details=[canonical] if canonical else [],
        )

    async def _check_viewport(self) -> SEOCheckResult:
        """检查 Viewport 设置"""
        viewport = await self.page.locator('meta[name="viewport"]').get_attribute("content")
        passed = bool(viewport and "width=device-width" in viewport)

        return SEOCheckResult(
            id="meta-viewport",
            name="Viewport 设置",
            passed=passed,
            score=100 if passed else 0,
            description="Viewport 设置正确" if passed else "缺少正确的 Viewport 设置",
            details=[viewport] if viewport else [],
        )

    async def _check_robots(self) -> SEOCheckResult:
        """检查 Robots Meta"""
        robots = await self.page.locator('meta[name="robots"]').get_attribute("content")

        if robots and "noindex" in robots.lower():
            return SEOCheckResult(
                id="robots",
                name="Robots Meta",
                passed=False,
                score=0,
                description="页面被设置为 noindex",
                details=[robots],
            )

        return SEOCheckResult(
            id="robots",
            name="Robots Meta",
            passed=True,
            score=100,
            description="页面可被索引" if not robots else f"Robots: {robots}",
            details=[robots] if robots else [],
        )

    async def _check_og_tags(self) -> SEOCheckResult:
        """检查 Open Graph 标签"""
        og_title = await self.page.locator('meta[property="og:title"]').get_attribute("content")
        og_description = await self.page.locator('meta[property="og:description"]').get_attribute("content")
        og_image = await self.page.locator('meta[property="og:image"]').get_attribute("content")

        tags = []
        if og_title:
            tags.append("og:title")
        if og_description:
            tags.append("og:description")
        if og_image:
            tags.append("og:image")

        score = (len(tags) / 3) * 100
        passed = len(tags) >= 2

        return SEOCheckResult(
            id="og-tags",
            name="Open Graph 标签",
            passed=passed,
            score=score,
            description=f"存在 {len(tags)}/3 个主要 OG 标签",
            details=tags,
        )

    async def _check_structured_data(self) -> SEOCheckResult:
        """检查结构化数据"""
        json_ld = await self.page.locator('script[type="application/ld+json"]').count()

        passed = json_ld > 0
        return SEOCheckResult(
            id="structured-data",
            name="结构化数据",
            passed=passed,
            score=100 if passed else 0,
            description=f"存在 {json_ld} 个结构化数据块" if passed else "缺少结构化数据",
        )

    async def _check_links(self) -> SEOCheckResult:
        """检查链接"""
        links = self.page.locator("a[href]")
        total = await links.count()

        broken_count = 0
        for i in range(min(total, 20)):  # 只检查前20个
            link = links.nth(i)
            href = await link.get_attribute("href")
            if href and href.startswith("javascript:"):
                broken_count += 1

        score = 100 if broken_count == 0 else max(0, 100 - broken_count * 10)
        passed = broken_count == 0

        return SEOCheckResult(
            id="links",
            name="链接检查",
            passed=passed,
            score=score,
            description=f"检查了 {min(total, 20)} 个链接",
            details=[f"{broken_count} 个问题链接"] if broken_count else [],
        )

    def generate_report(self, report: SEOReport) -> str:
        """生成报告"""
        lines = [
            "\n=== SEO 检查报告 ===\n",
            f"URL: {report.url}",
            f"总分: {report.total_score:.1f}/100",
            f"通过: {report.passed_count}/{len(report.checks)}\n",
        ]

        for check in report.checks:
            status = "✅" if check.passed else "❌"
            lines.append(f"{status} {check.name}: {check.description} ({check.score:.0f}分)")
            if check.details:
                for detail in check.details[:3]:
                    lines.append(f"   - {detail}")

        return "\n".join(lines)


def create_seo_checker(page: Page) -> SEOChecker:
    """创建 SEO 检查器实例"""
    return SEOChecker(page)
