"""自定义规则引擎：关键词匹配 + 用户规则管理"""




class RuleEngine:
    """用户自定义规则：关键词 AND/OR/NOT 组合"""

    @staticmethod
    def compile_rule(rule: dict) -> callable:
        """
        rule = {
            "type": "and"|"or"|"keyword"|"not",
            "children": [...],        # for and/or/not
            "keyword": "PD-L1",       # for keyword type
            "field": "title_abstract",  # title | abstract | title_abstract | all
            "case_sensitive": false,
        }
        Returns: callable(article_dict) -> bool
        """
        rule_type = rule.get("type", "keyword")

        if rule_type == "keyword":
            kw = rule.get("keyword", "")
            field = rule.get("field", "title_abstract")
            case = rule.get("case_sensitive", False)

            def _match(article: dict) -> bool:
                texts = []
                if field in ("title", "title_abstract", "all"):
                    texts.append(article.get("title", ""))
                if field in ("abstract", "title_abstract", "all"):
                    texts.append(article.get("abstract", "") or "")
                if field == "all":
                    texts.append(str(article.get("journal", "")))

                search_text = " ".join(texts)
                search_kw = kw
                if not case:
                    search_text = search_text.lower()
                    search_kw = kw.lower()
                return search_kw in search_text

            return _match

        elif rule_type == "not":
            child = RuleEngine.compile_rule(rule["children"][0]) if rule.get("children") else lambda x: False
            return lambda a: not child(a)

        elif rule_type == "or":
            children = [RuleEngine.compile_rule(c) for c in rule.get("children", [])]
            return lambda a: any(c(a) for c in children)

        elif rule_type == "and":
            children = [RuleEngine.compile_rule(c) for c in rule.get("children", [])]
            return lambda a: all(c(a) for c in children)

        return lambda a: True

    @staticmethod
    def compile_multi_rule(rules: list[dict], match_mode: str = "any") -> callable:
        """多条规则组合成一个大过滤器"""
        if not rules:
            return lambda a: True

        matchers = [RuleEngine.compile_rule(r) for r in rules]
        if match_mode == "any":
            return lambda a: any(m(a) for m in matchers)
        elif match_mode == "all":
            return lambda a: all(m(a) for m in matchers)
        else:
            return lambda a: any(m(a) for m in matchers)


# ─── 经典规则模式（快捷模板） ───

PRESET_RULES = {
    "drug_trial": {
        "name": "药物临床试验",
        "rule": {
            "type": "and",
            "children": [
                {"type": "keyword", "field": "title_abstract", "keyword": "trial"},
                {"type": "or", "children": [
                    {"type": "keyword", "field": "title_abstract", "keyword": "phase"},
                    {"type": "keyword", "field": "title_abstract", "keyword": "randomi"},
                ]},
            ],
        },
    },
    "chinese_population": {
        "name": "中国人群研究",
        "rule": {
            "type": "or",
            "children": [
                {"type": "keyword", "field": "all", "keyword": "China"},
                {"type": "keyword", "field": "all", "keyword": "Chinese"},
                {"type": "keyword", "field": "title_abstract", "keyword": "Han Chinese"},
            ],
        },
    },
    "biomarker_study": {
        "name": "生物标志物研究",
        "rule": {
            "type": "or",
            "children": [
                {"type": "keyword", "field": "title_abstract", "keyword": "biomarker"},
                {"type": "keyword", "field": "title_abstract", "keyword": "ctDNA"},
                {"type": "keyword", "field": "title_abstract", "keyword": "circulating tumor"},
                {"type": "keyword", "field": "title_abstract", "keyword": "PD-L1 expression"},
                {"type": "keyword", "field": "title_abstract", "keyword": "TMB"},
                {"type": "keyword", "field": "title_abstract", "keyword": "MSI"},
            ],
        },
    },
    "survival_endpoint": {
        "name": "OS/PFS 终点研究",
        "rule": {
            "type": "and",
            "children": [
                {"type": "keyword", "field": "title_abstract", "keyword": "overall survival"},
                {"type": "or", "children": [
                    {"type": "keyword", "field": "title_abstract", "keyword": "HR "},
                    {"type": "keyword", "field": "title_abstract", "keyword": "hazard ratio"},
                    {"type": "keyword", "field": "title_abstract", "keyword": "median"},
                ]},
            ],
        },
    },
    "novel_target": {
        "name": "新靶点/新机制",
        "rule": {
            "type": "or",
            "children": [
                {"type": "keyword", "field": "title", "keyword": "novel"},
                {"type": "keyword", "field": "title", "keyword": "first-in-human"},
                {"type": "keyword", "field": "title", "keyword": "first-in-class"},
                {"type": "keyword", "field": "title", "keyword": "new target"},
                {"type": "keyword", "field": "title", "keyword": "mechanism"},
            ],
        },
    },
}
