# Copyright (C) 2026 GoodData Corporation

"""Optional rule injection bundle logic for targeted rule routing."""

from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import Any, cast

import yaml

from aida_mcp.utils.aida_paths import DOT_AIDA, ENV_CONFIG_ROOT

logger = logging.getLogger(__name__)

# Global cache for injection bundles
_cached_injection_bundles: list[dict[str, object]] | None = None


def load_injection_bundles() -> list[dict[str, object]]:
    """
    Load configured injection bundles.

    Returns bundle dicts with keys: id, when, inject.
    """
    global _cached_injection_bundles
    if _cached_injection_bundles is not None:
        return _cached_injection_bundles

    config_root_override = os.environ.get(ENV_CONFIG_ROOT)
    if isinstance(config_root_override, str) and config_root_override.strip():
        config_root = Path(config_root_override.strip()).expanduser()
        if not config_root.is_absolute():
            config_root = (Path.cwd() / config_root).resolve()
    else:
        config_root = Path.cwd().resolve() / DOT_AIDA

    config_path = config_root / "rules_injection.yaml"
    if not config_path.exists():
        _cached_injection_bundles = []
        return _cached_injection_bundles

    try:
        with open(config_path, encoding="utf-8") as f:
            loaded = yaml.safe_load(f)
    except Exception as exc:
        logger.warning("Failed to load rule injection config %s: %s", config_path, exc)
        _cached_injection_bundles = []
        return _cached_injection_bundles

    if not isinstance(loaded, dict):
        _cached_injection_bundles = []
        return _cached_injection_bundles

    raw_bundles = cast(dict[str, Any], loaded).get("bundles")
    if not isinstance(raw_bundles, list):
        _cached_injection_bundles = []
        return _cached_injection_bundles

    bundles: list[dict[str, object]] = []
    for b in cast(list[object], raw_bundles):
        if isinstance(b, dict):
            bundles.append(cast(dict[str, object], b))
    _cached_injection_bundles = bundles
    return _cached_injection_bundles


def compute_inject_paths(*, query: str, file_context: list[str] | None) -> list[str]:
    """
    Compute best-effort injected rule paths from configured bundles.

    Matching is substring-based on lowercased query and file_context joined string.
    """
    ql = query.lower()
    ctxl = " ".join(file_context or []).lower()

    inject_paths: list[str] = []
    for bundle in load_injection_bundles():
        when = bundle.get("when")
        inject = bundle.get("inject")
        if not isinstance(when, dict) or not isinstance(inject, list):
            continue

        when_dict = cast(dict[str, Any], when)
        q_terms = when_dict.get("query_contains")
        ctx_terms = when_dict.get("file_context_contains")

        q_match = isinstance(q_terms, list) and any(isinstance(t, str) and t in ql for t in cast(list[object], q_terms))
        ctx_match = isinstance(ctx_terms, list) and any(
            isinstance(t, str) and t in ctxl for t in cast(list[object], ctx_terms)
        )

        if q_match or ctx_match:
            inject_paths.extend([p for p in cast(list[object], inject) if isinstance(p, str) and p])

    # Stable order, de-dupe
    seen: set[str] = set()
    unique: list[str] = []
    for p in inject_paths:
        if p in seen:
            continue
        seen.add(p)
        unique.append(p)
    return unique
