"""Content rule implementation - 文件内容规则实现."""

from __future__ import annotations

import re
from abc import ABC, abstractmethod
from typing import Any

from ...models.fileinfo import FileInfo, MatchInfo
from ..base import BaseRule


class BaseContentRule(BaseRule, ABC):
    """文件内容匹配规则 - 对可解析的文件适用（DOCX, PDF, XLSX 等）.

    需要子类实现 parse_content() 方法来提取文件内容。
    """

    def __init__(self, rule_data: dict[str, Any]) -> None:
        """初始化内容规则.

        Args:
            rule_data: 包含规则配置的字典
        """
        self.name = rule_data.get("name", "")
        self.pattern = rule_data.get("pattern", "")
        self.is_regex = rule_data.get("regex", False)
        self.case_sensitive = rule_data.get("case_sensitive", False)
        self.context_lines = rule_data.get("context_lines", 3)
        self.description = rule_data.get("description", "")

        if self.is_regex:
            flags = 0 if self.case_sensitive else re.IGNORECASE
            try:
                self.compiled_pattern = re.compile(self.pattern, flags | re.ASCII)
            except re.error as e:
                from ...models.logger import logger

                logger.warning(f"无效的正则表达式模式 '{self.pattern}': {e}")
                self.compiled_pattern = None
        else:
            self.compiled_pattern = None

    @abstractmethod
    def parse_content(self, fileinfo: FileInfo) -> str:
        """从文件中提取内容（由子类实现）.

        Args:
            fileinfo: 文件信息对象

        Returns
        -------
            提取的文本内容
        """
        pass

    def match(self, fileinfo: FileInfo) -> MatchInfo | None:
        """匹配文件内容.

        Args:
            fileinfo: 文件信息对象

        Returns
        -------
            如果匹配返回第一个 MatchInfo，否则返回 None
        """
        content = self.parse_content(fileinfo)
        if not content:
            return None

        # 使用 find_all_matches 获取所有匹配，然后返回第一个
        all_matches = self.find_all_matches(fileinfo, text=content)
        return all_matches[0] if all_matches else None

    def find_all_matches(self, fileinfo: FileInfo, *, text: str | None = None) -> list[MatchInfo]:
        """查找文件内容中的所有匹配项.

        Args:
            fileinfo: 文件信息对象
            text: 可选的预提取文本内容。如果提供，将直接使用；否则调用 parse_content() 提取

        Returns
        -------
            匹配结果列表
        """
        matches = []
        # 使用提供的文本或从文件中提取
        content = text if text is not None else self.parse_content(fileinfo)

        if not content or not self.pattern:
            return matches

        lines = content.split("\n")

        if self.is_regex and self.compiled_pattern:
            # 正则表达式匹配
            for line_num, line in enumerate(lines, 1):
                for match in self.compiled_pattern.finditer(line):
                    match_info = MatchInfo(
                        file_id=fileinfo.id,
                        rule_name=self.name,
                        rule_description=self.description,
                        match_type="regex",
                        analysis_type="content",
                        line_number=line_num,
                        match_text=match.group(),
                        start_pos=match.start(),
                        end_pos=match.end(),
                        context_lines=self._get_context(lines, line_num - 1),
                    )
                    matches.append(match_info)
        else:
            # 文本匹配
            search_text = self.pattern if self.case_sensitive else self.pattern.lower()
            for line_num, line in enumerate(lines, 1):
                compare_line = line if self.case_sensitive else line.lower()
                start = 0
                while True:
                    pos = compare_line.find(search_text, start)
                    if pos == -1:
                        break
                    match_info = MatchInfo(
                        file_id=fileinfo.id,
                        rule_name=self.name,
                        rule_description=self.description,
                        match_type="text",
                        analysis_type="content",
                        line_number=line_num,
                        match_text=line[pos : pos + len(self.pattern)],
                        start_pos=pos,
                        end_pos=pos + len(self.pattern),
                        context_lines=self._get_context(lines, line_num - 1),
                    )
                    matches.append(match_info)
                    start = pos + 1

        return matches

    def _match_content(self, content: str) -> bool:
        """检查内容是否匹配规则.

        Args:
            content: 文件内容

        Returns
        -------
            如果匹配返回 True
        """
        if not content or not self.pattern:
            return False

        if self.is_regex and self.compiled_pattern:
            return bool(self.compiled_pattern.search(content))
        compare_content = content if self.case_sensitive else content.lower()
        search_text = self.pattern if self.case_sensitive else self.pattern.lower()
        return search_text in compare_content

    def _get_context(self, lines: list[str], line_index: int) -> list[str]:
        """获取匹配项周围的上下文行.

        Args:
            lines: 所有文本行
            line_index: 匹配行的索引

        Returns
        -------
            上下文行列表
        """
        start = max(0, line_index - self.context_lines)
        end = min(len(lines), line_index + self.context_lines + 1)
        return lines[start:end]
