import os
import re
from typing import Any, Dict, List

import yaml

from brox.policy.schema import validate_policy


def evaluate_policy(diff_data: Dict[str, Any], policy_path: str) -> Dict[str, Any]:

    with open(policy_path) as f:
        policy = yaml.safe_load(f)

    validate_policy(policy)

    triggered_rules = []
    for rule in policy.get("rules", []):
        if evaluate_rule(rule, diff_data):
            triggered_rules.append(
                {
                    "id": rule["id"],
                    "action": rule["action"],
                    "message": rule["message"],
                }
            )

    decision = "pass"
    for rule in triggered_rules:
        if rule["action"] == "block":
            decision = "block"
            break
        elif rule["action"] == "require_approval":
            if not check_approval(rule.get("approval", {})):
                decision = "block"
                break
        elif rule["action"] == "warn":
            if decision == "pass":
                decision = "warn"

    return {"decision": decision, "triggered_rules": triggered_rules}


def evaluate_rule(rule: Dict[str, Any], diff_data: Dict[str, Any]) -> bool:
    when_clause = rule.get("when", {})

    if "capability_added" in when_clause:
        cap_name = when_clause["capability_added"]
        capabilities_added = diff_data.get("capabilities", {}).get("added", [])

        for cap in capabilities_added:
            if cap["capability"] == cap_name:
                if "scope_matches_any" in when_clause:
                    if scope_matches_any(cap["scope"], when_clause["scope_matches_any"]):
                        return True
                else:
                    return True

    if "capability_widened" in when_clause:
        cap_name = when_clause["capability_widened"]
        capabilities_widened = diff_data.get("capabilities", {}).get("widened", [])

        for cap in capabilities_widened:
            if cap["capability"] == cap_name:
                if "scope_matches_any" in when_clause:
                    if scope_matches_any(cap["to"], when_clause["scope_matches_any"]):
                        return True
                else:
                    return True

    if "asset_added_kind" in when_clause:
        kind = when_clause["asset_added_kind"]
        assets_added = diff_data.get("assets", {}).get("added", [])

        for asset in assets_added:
            if asset["kind"] == kind:
                return True

    if "asset_changed_kind" in when_clause:
        kind = when_clause["asset_changed_kind"]
        assets_changed = diff_data.get("assets", {}).get("changed", [])

        for asset in assets_changed:
            if asset["kind"] == kind:
                if "prompt_type" in when_clause:
                    prompt_type = when_clause["prompt_type"]
                    if prompt_type.lower() in asset["id"].lower():
                        return True
                else:
                    return True

    return False


def scope_matches_any(scope: str, patterns: List[str]) -> bool:
    for pattern in patterns:
        if scope_matches(scope, pattern):
            return True
    return False


def scope_matches(scope: str, pattern: str) -> bool:
    if pattern == "/**":
        return True

    regex_pattern = pattern.replace("**", "DOUBLESTAR").replace("*", "[^/]*").replace("DOUBLESTAR", ".*")

    regex_pattern = "^" + regex_pattern + "$"

    return re.match(regex_pattern, scope) is not None


def check_approval(approval_config: Dict[str, Any]) -> bool:
    mode = approval_config.get("mode")

    if mode == "pr_label":
        label = approval_config.get("label")
        pr_labels = os.environ.get("PR_LABELS", "").split(",")
        return label in pr_labels

    return False
