"""
Metadata Inference Service.
[AC-AISVC-RES-04] 元数据推断统一入口。
"""

import logging
from dataclasses import dataclass, field
from typing import Any

from sqlalchemy.ext.asyncio import AsyncSession

from app.services.mid.metadata_filter_builder import (
    FilterBuildResult,
    MetadataFilterBuilder,
)
from app.services.retrieval.strategy.config import (
    FilterMode,
    MetadataInferenceConfig,
)
from app.services.retrieval.strategy.pipeline_base import MetadataFilterResult

logger = logging.getLogger(__name__)


@dataclass
class InferenceContext:
    """元数据推断上下文。"""
    tenant_id: str
    query: str
    session_id: str | None = None
    user_id: str | None = None
    channel_type: str | None = None
    existing_context: dict[str, Any] = field(default_factory=dict)
    slot_state: Any = None


@dataclass
class InferenceResult:
    """元数据推断结果。"""
    filter_result: MetadataFilterResult
    inferred_fields: dict[str, Any] = field(default_factory=dict)
    confidence_scores: dict[str, float] = field(default_factory=dict)
    overall_confidence: float | None = None
    inference_source: str = "unknown"


class MetadataInferenceService:
    """
    元数据推断统一入口。【AC-AISVC-RES-04】
    
    职责：
    1. 统一的元数据推断入口（策略无关）
    2. 根据置信度决定 hard/soft filter 模式
    3. 与现有 MetadataFilterBuilder 保持一致
    """
    
    def __init__(
        self,
        session: AsyncSession,
        config: MetadataInferenceConfig | None = None,
    ):
        self._session = session
        self._config = config or MetadataInferenceConfig()
        self._filter_builder: MetadataFilterBuilder | None = None
    
    async def infer(self, ctx: InferenceContext) -> InferenceResult:
        """执行元数据推断。【AC-AISVC-RES-04】"""
        logger.info(
            f"[MetadataInference] Starting inference: tenant={ctx.tenant_id}, "
            f"query={ctx.query[:50]}..."
        )
        
        if self._filter_builder is None:
            self._filter_builder = MetadataFilterBuilder(self._session)
        
        effective_context = dict(ctx.existing_context)
        
        if ctx.slot_state:
            effective_context = await self._merge_slot_state(
                effective_context, ctx.slot_state
            )
        
        build_result = await self._filter_builder.build_filter(
            tenant_id=ctx.tenant_id,
            context=effective_context,
        )
        
        confidence = self._calculate_confidence(build_result, effective_context)
        filter_mode = self._config.determine_filter_mode(confidence)
        
        filter_result = MetadataFilterResult(
            filter_dict=build_result.applied_filter,
            filter_mode=filter_mode,
            confidence=confidence,
            missing_required_slots=build_result.missing_required_slots,
            debug_info=build_result.debug_info,
        )
        
        logger.info(
            f"[MetadataInference] Inference completed: filter_mode={filter_mode.value}, "
            f"confidence={confidence}"
        )
        
        return InferenceResult(
            filter_result=filter_result,
            inferred_fields=build_result.applied_filter,
            overall_confidence=confidence,
            inference_source="metadata_filter_builder",
        )
    
    async def _merge_slot_state(
        self, context: dict[str, Any], slot_state: Any
    ) -> dict[str, Any]:
        """合并槽位状态到上下文。"""
        if hasattr(slot_state, 'filled_slots'):
            for slot_key, slot_value in slot_state.filled_slots.items():
                if slot_key not in context:
                    context[slot_key] = slot_value
        return context
    
    def _calculate_confidence(
        self, build_result: FilterBuildResult, context: dict[str, Any]
    ) -> float | None:
        """计算推断置信度。"""
        if build_result.missing_required_slots:
            return 0.3
        if not build_result.applied_filter:
            return None
        if not context:
            return 0.5
        applied_ratio = len(build_result.applied_filter) / max(len(context), 1)
        if applied_ratio >= 0.8:
            return 0.9
        elif applied_ratio >= 0.5:
            return 0.7
        return 0.5
