"""HTML Generator 模块 - 生成匹配详情的 HTML 预览(使用 Jinja2 模板)."""

from __future__ import annotations

from datetime import datetime, timezone
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..models.fileinfo import MatchInfo

from ..models.logger import logger


class MatchHTMLGenerator:
    """匹配详情 HTML 生成器 - 使用 Jinja2 模板."""

    _template = None

    @classmethod
    def _load_template(cls) -> None:
        """加载 Jinja2 模板."""
        if cls._template is None:
            try:
                from jinja2 import Environment, FileSystemLoader
                from jinja2.exceptions import TemplateNotFound

                # 获取模板文件路径
                template_dir = Path(__file__).parent.parent / "assets" / "templates"
                env = Environment(
                    loader=FileSystemLoader(str(template_dir)),
                    autoescape=True,
                    trim_blocks=True,
                    lstrip_blocks=True,
                )
                cls._template = env.get_template("match_details.html")
                logger.info("Jinja2 模板加载成功")
            except ImportError:
                # 如果没有安装 Jinja2,使用内置模板
                cls._template = None
                logger.warning("Jinja2 模板加载失败,将使用内置模板")
            except (TemplateNotFound, FileNotFoundError, OSError):
                # 模板文件不存在或读取失败,使用内置模板
                logger.warning("匹配详情模板加载失败,将使用内置模板")
                cls._template = None

    @classmethod
    def generate_html(
        cls,
        file_name: str,
        matches: list[MatchInfo],
        file_size: int = 0,
        processing_time: float = 0.0,
    ) -> str:
        """生成完整的 HTML 内容.

        Args:
            file_name: 文件名
            matches: 匹配信息列表

        Returns
        -------
            HTML 字符串
        """
        # 准备模板数据
        template_data = cls._prepare_template_data(file_name, matches, file_size, processing_time)

        # 使用 Jinja2 模板渲染
        if cls._template is None:
            cls._load_template()

        if cls._template is not None:
            logger.info("使用 Jinja2 模板渲染 HTML")
            return cls._template.render(**template_data)
        logger.info("使用内置模板渲染 HTML")
        return cls._generate_builtin_html(file_name, matches)

    @classmethod
    def _prepare_template_data(
        cls,
        file_name: str,
        matches: list[MatchInfo],
        file_size: int = 0,
        processing_time: float = 0.0,
    ) -> dict:
        """准备模板数据.

        Args:
            file_name: 文件名
            matches: 匹配信息列表

        Returns
        -------
            模板数据字典
        """
        # 按规则分组统计
        rule_stats_dict = {}
        for match in matches:
            rule_name = match.rule_name
            if rule_name not in rule_stats_dict:
                rule_stats_dict[rule_name] = {
                    "count": 0,
                    "description": match.rule_description,
                    "type": match.analysis_type,
                }
            rule_stats_dict[rule_name]["count"] += 1

        # 格式化规则统计
        rule_stats = []
        for rule_name, stats in sorted(rule_stats_dict.items()):
            type_class_map = {"filename": "filename", "content": "content", "zipfile": "zipfile"}
            type_class = type_class_map.get(stats["type"].lower(), "content")

            rule_stats.append({
                "rule_name": rule_name,
                "count": stats["count"],
                "description": stats["description"],
                "analysis_type": stats["type"],
                "type_class": type_class,
            })

        # 格式化匹配详情
        formatted_matches = []
        for idx, match in enumerate(matches, 1):
            type_class_map = {"filename": "filename", "content": "content", "zipfile": "zipfile"}
            match_type = getattr(match, "match_type", "content").lower()
            type_class = type_class_map.get(match_type, "content")

            # 限制上下文显示行数
            context_lines = getattr(match, "context_lines", [])
            context_limited = context_lines[:2] if len(context_lines) > 2 else context_lines

            formatted_matches.append({
                "index": idx,
                "rule_name": match.rule_name,
                "rule_description": match.rule_description or "",
                "match_type": match.match_type,
                "analysis_type": match.analysis_type,
                "line_number": match.line_number,
                "match_text": match.match_text,
                "context_lines_limited": context_limited,
                "context_total_lines": len(context_lines),
                "has_more_context": len(context_lines) > 2,
                "type_class": type_class,
            })

        # 文件大小格式化
        file_size_formatted = cls._format_file_size(file_size)
        processing_time_str = f"{processing_time:.3f}"

        return {
            "file_name": file_name,
            "generation_time": datetime.now(tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S"),
            "file_size_formatted": file_size_formatted,
            "match_count": len(matches),
            "processing_time": processing_time_str,
            "unique_rules_count": len(rule_stats_dict),
            "rule_stats": rule_stats,
            "matches": formatted_matches,
        }

    @classmethod
    def _generate_builtin_html(cls, file_name: str, matches: list[MatchInfo]) -> str:
        """生成内置 HTML(当 Jinja2 不可用时).

        Args:
            file_name: 文件名
            matches: 匹配信息列表

        Returns
        -------
            HTML 字符串
        """
        # 简化的内置实现
        return f"""<!DOCTYPE html>
<html>
<head>
    <title>匹配详情 - {file_name}</title>
</head>
<body>
    <h1>📋 文件匹配分析报告</h1>
    <p>文件名:{file_name}</p>
    <p>共 {len(matches)} 个匹配</p>
</body>
</html>"""

    @staticmethod
    def _format_file_size(size: int) -> str:
        """格式化文件大小显示.

        Args:
            size: 字节数

        Returns
        -------
            格式化后的大小字符串
        """
        if size < 1024:
            return f"{size} B"
        if size < 1024 * 1024:
            return f"{size / 1024:.1f} KB"
        if size < 1024 * 1024 * 1024:
            return f"{size / (1024 * 1024):.1f} MB"
        return f"{size / (1024 * 1024 * 1024):.1f} GB"
