"""
Intent Hint Tool for Mid Platform.
[AC-IDMP-02, AC-IDMP-16] Lightweight intent recognition and routing suggestion.
[AC-MRS-13] 只消费 field_roles 包含 routing_signal 的字段

This tool provides a "soft signal" for policy routing decisions.
It does NOT make final decisions - policy_router retains final authority.
"""

import logging
import time
from dataclasses import dataclass
from typing import Any

from sqlalchemy.ext.asyncio import AsyncSession

from app.models.mid.schemas import (
    ExecutionMode,
    HighRiskScenario,
    IntentHintOutput,
    ToolCallStatus,
    ToolCallTrace,
    ToolType,
)
from app.models.entities import FieldRole
from app.services.intent.router import IntentRouter
from app.services.intent.rule_service import IntentRuleService
from app.services.mid.role_based_field_provider import RoleBasedFieldProvider

logger = logging.getLogger(__name__)

DEFAULT_HIGH_RISK_KEYWORDS: dict[HighRiskScenario, list[str]] = {
    HighRiskScenario.REFUND: ["退款", "退货", "退钱", "退费", "还钱", "退款申请"],
    HighRiskScenario.COMPLAINT_ESCALATION: ["投诉", "升级投诉", "举报", "12315", "消费者协会"],
    HighRiskScenario.PRIVACY_SENSITIVE_PROMISE: ["承诺", "保证", "一定", "肯定能", "绝对", "担保"],
    HighRiskScenario.TRANSFER: ["转人工", "人工客服", "人工服务", "真人", "人工"],
}

LOW_CONFIDENCE_THRESHOLD = 0.3
DEFAULT_TIMEOUT_MS = 500


@dataclass
class IntentHintConfig:
    """Configuration for intent hint tool."""
    enabled: bool = True
    timeout_ms: int = DEFAULT_TIMEOUT_MS
    top_n: int = 3
    low_confidence_threshold: float = LOW_CONFIDENCE_THRESHOLD


class IntentHintTool:
    """
    [AC-IDMP-02, AC-IDMP-16] Lightweight intent hint tool.
    [AC-MRS-13] 只消费 field_roles 包含 routing_signal 的字段
    
    Provides soft signals for policy routing:
    - Intent recognition via existing rule engine
    - High-risk scenario detection
    - Routing suggestions (not final decisions)
    
    The policy_router consumes these hints but retains final decision authority.
    """
    
    def __init__(
        self,
        session: AsyncSession,
        config: IntentHintConfig | None = None,
    ):
        self._session = session
        self._config = config or IntentHintConfig()
        self._rule_service = IntentRuleService(session)
        self._router = IntentRouter()
        self._role_provider = RoleBasedFieldProvider(session)
    
    async def execute(
        self,
        message: str,
        tenant_id: str,
        history: list[dict[str, Any]] | None = None,
        top_n: int | None = None,
        context: dict[str, Any] | None = None,
    ) -> IntentHintOutput:
        """
        [AC-IDMP-02] Execute intent hint analysis.
        [AC-MRS-13] 只消费 routing_signal 角色的字段
        
        Args:
            message: User input message
            tenant_id: Tenant ID for rule lookup
            history: Optional conversation history
            top_n: Number of top suggestions (default from config)
            context: Optional context with routing_signal fields
        
        Returns:
            IntentHintOutput with routing suggestions
        """
        start_time = time.time()
        
        routing_signal_fields = await self._role_provider.get_routing_signal_field_keys(tenant_id)
        logger.info(
            f"[AC-MRS-13] Retrieved {len(routing_signal_fields)} routing_signal fields for tenant={tenant_id}: {routing_signal_fields}"
        )
        
        routing_context = {}
        if context:
            routing_context = {k: v for k, v in context.items() if k in routing_signal_fields}
            if routing_context:
                logger.info(
                    f"[AC-MRS-13] Applied routing_signal context: {list(routing_context.keys())}"
                )
        
        if not self._config.enabled:
            return IntentHintOutput(
                intent=None,
                confidence=0.0,
                response_type=None,
                suggested_mode=None,
                fallback_reason_code="tool_disabled",
                duration_ms=0,
            )
        
        try:
            high_risk_scenario = self._check_high_risk(message)
            if high_risk_scenario:
                logger.info(
                    f"[AC-IDMP-05, AC-IDMP-20] High-risk detected in hint: {high_risk_scenario}"
                )
                duration_ms = int((time.time() - start_time) * 1000)
                return IntentHintOutput(
                    intent=None,
                    confidence=1.0,
                    response_type="flow" if high_risk_scenario != HighRiskScenario.TRANSFER else "transfer",
                    suggested_mode=ExecutionMode.TRANSFER if high_risk_scenario == HighRiskScenario.TRANSFER else ExecutionMode.MICRO_FLOW,
                    high_risk_detected=True,
                    fallback_reason_code=f"high_risk_{high_risk_scenario.value}",
                    duration_ms=duration_ms,
                )
            
            rules = await self._rule_service.get_enabled_rules_for_matching(tenant_id)
            
            if not rules:
                logger.info(f"[AC-IDMP-02] No intent rules found for tenant: {tenant_id}")
                duration_ms = int((time.time() - start_time) * 1000)
                return IntentHintOutput(
                    intent=None,
                    confidence=0.0,
                    response_type="rag",
                    suggested_mode=ExecutionMode.AGENT,
                    fallback_reason_code="no_rules_configured",
                    duration_ms=duration_ms,
                )
            
            match_result = self._router.match(message, rules)
            
            if match_result:
                rule = match_result.rule
                confidence = 0.8
                
                suggested_mode = self._determine_suggested_mode(
                    rule.response_type,
                    confidence,
                )
                
                duration_ms = int((time.time() - start_time) * 1000)
                logger.info(
                    f"[AC-IDMP-02] Intent hint matched: intent={rule.name}, "
                    f"response_type={rule.response_type}, confidence={confidence}"
                )
                
                return IntentHintOutput(
                    intent=rule.name,
                    confidence=confidence,
                    response_type=rule.response_type,
                    suggested_mode=suggested_mode,
                    target_flow_id=str(rule.flow_id) if rule.flow_id else None,
                    target_kb_ids=rule.target_kb_ids,
                    duration_ms=duration_ms,
                )
            
            duration_ms = int((time.time() - start_time) * 1000)
            logger.info(
                f"[AC-IDMP-02] No intent matched, suggesting agent mode with low confidence"
            )
            
            return IntentHintOutput(
                intent=None,
                confidence=0.2,
                response_type="rag",
                suggested_mode=ExecutionMode.AGENT,
                fallback_reason_code="no_intent_matched",
                duration_ms=duration_ms,
            )
        
        except Exception as e:
            duration_ms = int((time.time() - start_time) * 1000)
            logger.error(f"[AC-IDMP-02] Intent hint failed: {e}")
            
            return IntentHintOutput(
                intent=None,
                confidence=0.0,
                response_type=None,
                suggested_mode=ExecutionMode.FIXED,
                fallback_reason_code=f"hint_error: {str(e)[:50]}",
                duration_ms=duration_ms,
            )
    
    def _check_high_risk(self, message: str) -> HighRiskScenario | None:
        """
        [AC-IDMP-05, AC-IDMP-20] Check for high-risk scenarios.
        
        Returns the first matched high-risk scenario or None.
        """
        message_lower = message.lower()
        
        for scenario, keywords in DEFAULT_HIGH_RISK_KEYWORDS.items():
            for keyword in keywords:
                if keyword.lower() in message_lower:
                    return scenario
        
        return None
    
    def _determine_suggested_mode(
        self,
        response_type: str,
        confidence: float,
    ) -> ExecutionMode:
        """
        Determine suggested execution mode based on response type and confidence.
        """
        if confidence < self._config.low_confidence_threshold:
            return ExecutionMode.FIXED
        
        mode_mapping = {
            "fixed": ExecutionMode.FIXED,
            "transfer": ExecutionMode.TRANSFER,
            "flow": ExecutionMode.MICRO_FLOW,
            "rag": ExecutionMode.AGENT,
        }
        
        return mode_mapping.get(response_type, ExecutionMode.AGENT)
    
    def create_trace(
        self,
        result: IntentHintOutput,
    ) -> ToolCallTrace:
        """Create ToolCallTrace for this tool execution."""
        status = ToolCallStatus.OK
        if result.fallback_reason_code and "error" in result.fallback_reason_code:
            status = ToolCallStatus.ERROR
        
        return ToolCallTrace(
            tool_name="intent_hint",
            tool_type=ToolType.INTERNAL,
            duration_ms=result.duration_ms,
            status=status,
            error_code=result.fallback_reason_code if status == ToolCallStatus.ERROR else None,
            result_digest=f"intent={result.intent}, mode={result.suggested_mode}",
        )


async def intent_hint_handler(
    message: str,
    tenant_id: str,
    history: list[dict[str, Any]] | None = None,
    top_n: int | None = None,
    context: dict[str, Any] | None = None,
    session: AsyncSession | None = None,
    config: IntentHintConfig | None = None,
) -> dict[str, Any]:
    """
    Handler function for ToolRegistry registration.
    [AC-MRS-13] 支持 context 参数用于 routing_signal 字段
    
    This is the async handler that gets registered to ToolRegistry.
    """
    if not session:
        return {
            "success": False,
            "error": "Database session required",
            "output": None,
        }
    
    tool = IntentHintTool(session=session, config=config)
    result = await tool.execute(
        message=message,
        tenant_id=tenant_id,
        history=history,
        top_n=top_n,
        context=context,
    )
    
    return {
        "success": True,
        "output": result.model_dump(),
        "hint": result,
    }


def register_intent_hint_tool(
    registry: Any,
    session: AsyncSession,
    config: IntentHintConfig | None = None,
) -> None:
    """
    [AC-IDMP-19] Register intent_hint tool to ToolRegistry.
    [AC-MRS-13] 支持 context 参数用于 routing_signal 字段
    
    Args:
        registry: ToolRegistry instance
        session: Database session for intent rule lookup
        config: Tool configuration
    """
    from app.models.mid.schemas import ToolType
    
    effective_config = config or IntentHintConfig()
    
    async def handler(
        message: str,
        tenant_id: str,
        history: list[dict[str, Any]] | None = None,
        top_n: int | None = None,
        context: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        return await intent_hint_handler(
            message=message,
            tenant_id=tenant_id,
            history=history,
            top_n=top_n,
            context=context,
            session=session,
            config=effective_config,
        )
    
    registry.register(
        name="intent_hint",
        description="[AC-IDMP-02, AC-IDMP-16, AC-MRS-13] Lightweight intent recognition and routing suggestion tool (only consumes routing_signal fields)",
        handler=handler,
        tool_type=ToolType.INTERNAL,
        version="1.0.0",
        enabled=True,
        timeout_ms=min(effective_config.timeout_ms, 500),
        metadata={
            "low_confidence_threshold": effective_config.low_confidence_threshold,
            "top_n": effective_config.top_n,
            "supports_routing_signal_filter": True,
            "when_to_use": "当用户意图不明确、需要给 policy_router 提供软路由信号时使用。",
            "when_not_to_use": "当已经明确进入固定模式/流程模式，或已有确定意图结果时不重复调用。",
            "parameters": {
                "type": "object",
                "properties": {
                    "message": {"type": "string", "description": "用户输入原文"},
                    "tenant_id": {"type": "string", "description": "租户 ID"},
                    "history": {"type": "array", "description": "会话历史（可选）"},
                    "top_n": {"type": "integer", "description": "返回建议数量（可选）"},
                    "context": {"type": "object", "description": "上下文字段（仅 routing_signal 字段会被消费）"}
                },
                "required": ["message", "tenant_id"]
            },
            "example_action_input": {
                "message": "我想退款，但是也想先咨询下怎么处理",
                "tenant_id": "default",
                "top_n": 3,
                "context": {"order_status": "delivered", "channel": "web"}
            },
            "result_interpretation": "关注输出中的 intent / confidence / suggested_mode。该工具只提供建议，不做最终决策。"
        },
    )
    
    logger.info(
        f"[AC-IDMP-19] intent_hint tool registered: timeout_ms={effective_config.timeout_ms}"
    )
