from __future__ import annotations

import os
import re
from functools import lru_cache
from pathlib import Path
from typing import Any

import yaml


def get_gates_config_path() -> Path:
    override = os.getenv("LEADTECH_GATES_CONFIG")
    if override:
        return Path(override).resolve()
    return Path(__file__).resolve().parents[2] / "config" / "gates.yaml"


@lru_cache(maxsize=4)
def load_gates_config(config_path: str | None = None) -> dict[str, Any]:
    path = Path(config_path).resolve() if config_path else get_gates_config_path()
    payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
    return payload if isinstance(payload, dict) else {}


def get_gate_labels() -> list[str]:
    config = load_gates_config()
    labels = config.get("labels", [])
    return [str(label) for label in labels]


def _matches_any(patterns: list[str], text: str) -> bool:
    return any(re.search(pattern, text, re.IGNORECASE) for pattern in patterns)


def apply_text_rules(tool_name: str, domain: str, text: str, strict: bool) -> list[dict[str, str]]:
    config = load_gates_config()
    rules = config.get(tool_name, [])
    findings: list[dict[str, str]] = []

    for rule in rules:
        if not isinstance(rule, dict):
            continue

        domains = rule.get("domains", [])
        if domains and domain not in domains:
            continue

        if_any = [str(pattern) for pattern in rule.get("if_any", [])]
        if if_any and not _matches_any(if_any, text):
            continue

        unless_any = [str(pattern) for pattern in rule.get("unless_any", [])]
        if unless_any and _matches_any(unless_any, text):
            continue

        required_any = [str(pattern) for pattern in rule.get("required_any", [])]
        if required_any and _matches_any(required_any, text):
            continue

        for action in rule.get("actions", []):
            if not isinstance(action, dict):
                continue
            if action.get("strict_only") and not strict:
                continue
            findings.append(
                {
                    "target": str(action["target"]),
                    "message": str(action["message"]),
                    "rule_id": str(rule.get("id", "")),
                }
            )

    return findings
