"""
审批策略抽象。

提供 4 种内置策略 + 可扩展 callable 策略。
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Callable

from cmdc.types import Event


class ApprovalPolicy(ABC):
    """审批策略基类。

    处理 ``approval_required`` 事件，决定自动批准还是拒绝。
    """

    @abstractmethod
    def decide(self, event: Event) -> bool:
        """根据事件决定是否批准。

        Returns:
            True 表示批准，False 表示拒绝。
        """


class AutoApprove(ApprovalPolicy):
    """自动批准所有工具调用。

    警告：仅用于受信任的环境，不建议在生产中无条件使用。
    """

    def decide(self, event: Event) -> bool:
        return True


class AutoReject(ApprovalPolicy):
    """自动拒绝所有工具调用（测试用）。"""

    def decide(self, event: Event) -> bool:
        return False


class PromptApproval(ApprovalPolicy):
    """在终端提示用户手动审批。

    收到 approval_required 事件时，打印工具名和参数，等待用户输入 y/n。
    """

    def decide(self, event: Event) -> bool:
        tool_name = event.data.get("toolName", "unknown")
        args = event.data.get("args", {})
        hint = event.data.get("hint", "")
        print(f"\n[HITL] 工具 {tool_name!r} 请求审批")
        if args:
            print(f"  参数: {args}")
        if hint:
            print(f"  提示: {hint}")
        while True:
            answer = input("  批准? [y/N]: ").strip().lower()
            if answer in ("y", "yes"):
                return True
            if answer in ("n", "no", ""):
                return False
            print("  请输入 y 或 n")


class CallableApproval(ApprovalPolicy):
    """包装任意 callable 为审批策略。

    用法::

        policy = CallableApproval(lambda e: e.data.get("toolName") != "Shell")
    """

    def __init__(self, func: Callable[[Event], bool]) -> None:
        self._func = func

    def decide(self, event: Event) -> bool:
        return bool(self._func(event))


def make_policy(policy: "ApprovalPolicyLike") -> ApprovalPolicy:
    """将便捷写法转换为 ApprovalPolicy 实例。

    支持：
        - ``"auto_approve"`` 字符串
        - ``"auto_reject"`` 字符串
        - ``"prompt"`` 字符串（终端交互）
        - ``ApprovalPolicy`` 子类实例
        - 任意 callable ``(Event) -> bool``
    """
    if isinstance(policy, str):
        if policy == "auto_approve":
            return AutoApprove()
        if policy == "auto_reject":
            return AutoReject()
        if policy == "prompt":
            return PromptApproval()
        raise ValueError(f"未知审批策略字符串: {policy!r}")
    if isinstance(policy, ApprovalPolicy):
        return policy
    if callable(policy):
        return CallableApproval(policy)
    raise TypeError(f"无法识别的审批策略类型: {type(policy)}")


# 类型别名（方便用户使用）
ApprovalPolicyLike = (
    ApprovalPolicy
    | Callable[[Event], bool]
    | str
)
