"""Approval triage logic for Grukk.

Grukk evaluates pending approval requests from peon-loops and decides
whether to auto-resolve them or escalate to the King.  The decision
framework is defined in the system prompt (personality.py) and implemented
here as structured logic.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass
from enum import Enum
from typing import Any

from peon_mcp.grukk.api import GrukkAPIClient

log = logging.getLogger("peon-grukk")

# Keywords in approval titles that indicate routine operations safe to auto-approve.
_ROUTINE_KEYWORDS = frozenset({
    "merge", "update", "format", "formatting", "lint", "linting",
    "style", "retry", "reformat", "bump", "version", "deps",
    "dependency", "dependencies", "changelog",
})

# Keywords that indicate destructive or security-sensitive operations.
_DANGEROUS_KEYWORDS = frozenset({
    "delete", "drop", "force-push", "force push", "destroy", "remove",
    "secret", "auth", "permission", "security", "credential", "token",
})


class TriageAction(Enum):
    """What Grukk should do with an approval request."""

    AUTO_APPROVE = "auto_approve"
    AUTO_REJECT = "auto_reject"
    ESCALATE = "escalate"
    ESCALATE_WITH_RECOMMENDATION = "escalate_with_recommendation"


class RiskLevel(Enum):
    """Risk classification for an approval."""

    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


@dataclass
class TriageDecision:
    """Result of evaluating a pending approval."""

    action: TriageAction
    risk: RiskLevel
    reason: str
    recommendation: str | None = None


class ApprovalTriager:
    """Evaluates pending approvals and decides: auto-resolve or escalate to King.

    The triager uses a combination of rule-based heuristics and precedent
    lookup (via resolved approvals) to classify each approval.  When uncertain,
    it always escalates -- Grukk would rather bother the King than make a bad
    call.

    Parameters
    ----------
    client:
        :class:`GrukkAPIClient` instance for API access.
    """

    def __init__(self, client: GrukkAPIClient) -> None:
        self.client = client

    async def evaluate(self, approval: dict[str, Any]) -> TriageDecision:
        """Evaluate a single pending approval and return a triage decision.

        Parameters
        ----------
        approval:
            The approval request payload from the API.  Expected fields
            include ``priority``, ``approval_type``, ``title``, ``context``,
            ``task_id``, ``project_id``.

        Returns
        -------
        TriageDecision
            The action Grukk should take, risk level, and reasoning.
        """
        priority = (approval.get("priority") or "").lower()
        title = (approval.get("title") or "").lower()
        approval_type = (approval.get("approval_type") or "").lower()
        project_id = approval.get("project_id", "")

        # ---- Rule 1: Critical priority always escalates immediately ----
        if priority == "critical":
            log.info("Approval '%s' is critical priority -- escalating to King.", title)
            return TriageDecision(
                action=TriageAction.ESCALATE,
                risk=RiskLevel.CRITICAL,
                reason="Priority is critical -- Grukk always send critical items to King.",
                recommendation="Grukk think King should review this one personally.",
            )

        # ---- Rule 2: Dangerous/destructive operations -> escalate ----
        risk = self._classify_risk(approval)
        if risk in (RiskLevel.HIGH, RiskLevel.CRITICAL):
            log.info("Approval '%s' classified as %s risk -- escalating.", title, risk.value)
            return TriageDecision(
                action=TriageAction.ESCALATE,
                risk=risk,
                reason=f"Grukk detect risky operation in '{title}' -- better ask King.",
                recommendation="Grukk recommend King review before approving.",
            )

        # ---- Rule 3: Check for precedent (previously approved similar title) ----
        precedents = self._check_precedent(approval_type, project_id, title)
        if precedents:
            prev = precedents[0]
            prev_response = prev.get("response", "approved")
            log.info(
                "Approval '%s' has precedent -- auto-approving based on prior decision.",
                title,
            )
            return TriageDecision(
                action=TriageAction.AUTO_APPROVE,
                risk=RiskLevel.LOW,
                reason=(
                    f"Grukk find precedent -- King approved similar request "
                    f"'{prev.get('title', 'unknown')}' before.  Auto-approving."
                ),
                recommendation=prev_response,
            )

        # ---- Rule 4: Routine operations -> auto-approve ----
        title_words = set(title.split())
        if title_words & _ROUTINE_KEYWORDS:
            log.info("Approval '%s' looks routine -- auto-approving.", title)
            return TriageDecision(
                action=TriageAction.AUTO_APPROVE,
                risk=RiskLevel.LOW,
                reason=f"Grukk see routine operation '{title}' -- auto-approve.",
            )

        # ---- Default: escalate with context ----
        log.info("Approval '%s' unclear -- escalating to King with recommendation.", title)
        return TriageDecision(
            action=TriageAction.ESCALATE_WITH_RECOMMENDATION,
            risk=RiskLevel.MEDIUM,
            reason=f"Grukk not sure about '{title}' -- escalating to King with context.",
            recommendation="Grukk think this probably okay, but King should decide.",
        )

    def _check_precedent(
        self, approval_type: str, project_id: str, title: str,
    ) -> list[dict[str, Any]]:
        """Look up similar past approvals for precedent.

        Queries recently resolved approvals and checks if any share the same
        title (case-insensitive).
        """
        resolved = self.client.get_resolved_approvals(limit=50)
        if not resolved:
            return []

        title_lower = title.lower()
        matches = [
            r for r in resolved
            if (r.get("title") or "").lower() == title_lower
            and r.get("status") in ("approved", "resolved")
        ]
        return matches

    def _classify_risk(self, approval: dict[str, Any]) -> RiskLevel:
        """Classify the risk level of an approval based on its type and context.

        Rules:
        - Critical priority -> CRITICAL
        - Destructive operations (delete, force-push, drop) -> HIGH
        - Multi-project or security-sensitive changes -> HIGH
        - Unknown/first-time patterns -> MEDIUM
        - Routine transitions, retries, formatting -> LOW
        """
        priority = (approval.get("priority") or "").lower()
        title = (approval.get("title") or "").lower()
        context = (approval.get("context") or "").lower()
        combined = f"{title} {context}"

        if priority == "critical":
            return RiskLevel.CRITICAL

        # Check for dangerous keywords in title or context.
        for keyword in _DANGEROUS_KEYWORDS:
            if keyword in combined:
                return RiskLevel.HIGH

        # Check for routine keywords.
        title_words = set(title.split())
        if title_words & _ROUTINE_KEYWORDS:
            return RiskLevel.LOW

        return RiskLevel.MEDIUM
