"""
Intent rule monitoring service for AI Service.
[AC-AISVC-97, AC-AISVC-98] Intent rule statistics and hit records.
"""

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

from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.entities import ChatMessage, IntentRule

logger = logging.getLogger(__name__)


@dataclass
class IntentRuleStats:
    """Statistics for a single intent rule."""

    rule_id: str
    rule_name: str
    hit_count: int
    hit_rate: float
    avg_response_time: float
    last_hit_time: str | None
    response_type: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "ruleId": self.rule_id,
            "ruleName": self.rule_name,
            "hitCount": self.hit_count,
            "hitRate": self.hit_rate,
            "avgResponseTime": self.avg_response_time,
            "lastHitTime": self.last_hit_time,
            "responseType": self.response_type,
        }


@dataclass
class IntentRuleHitRecord:
    """A single hit record for an intent rule."""

    conversation_id: str
    session_id: str
    user_message: str
    matched_keywords: list[str]
    matched_patterns: list[str]
    response_type: str
    execution_result: str
    hit_time: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "conversationId": self.conversation_id,
            "sessionId": self.session_id,
            "userMessage": self.user_message,
            "matchedKeywords": self.matched_keywords,
            "matchedPatterns": self.matched_patterns,
            "responseType": self.response_type,
            "executionResult": self.execution_result,
            "hitTime": self.hit_time,
        }


@dataclass
class IntentRuleStatsResult:
    """Result of intent rule statistics query."""

    total_hits: int
    total_conversations: int
    hit_rate: float
    rules: list[IntentRuleStats]

    def to_dict(self) -> dict[str, Any]:
        return {
            "totalHits": self.total_hits,
            "totalConversations": self.total_conversations,
            "hitRate": self.hit_rate,
            "rules": [r.to_dict() for r in self.rules],
        }


class IntentMonitor:
    """
    [AC-AISVC-97, AC-AISVC-98] Intent rule monitoring service.

    Features:
    - Aggregate rule hit statistics
    - Query hit records for a specific rule
    - Calculate hit rates and average response times
    """

    def __init__(self, session: AsyncSession):
        self._session = session

    async def get_rule_stats(
        self,
        tenant_id: str,
        start_date: datetime | None = None,
        end_date: datetime | None = None,
        response_type: str | None = None,
    ) -> IntentRuleStatsResult:
        """
        [AC-AISVC-97] Get aggregated statistics for all intent rules.

        Args:
            tenant_id: Tenant ID for isolation
            start_date: Optional start date filter
            end_date: Optional end date filter
            response_type: Optional response type filter

        Returns:
            IntentRuleStatsResult with aggregated statistics
        """
        stmt = select(IntentRule).where(IntentRule.tenant_id == tenant_id)

        if response_type:
            stmt = stmt.where(IntentRule.response_type == response_type)

        result = await self._session.execute(stmt)
        rules = result.scalars().all()

        total_hits = sum(r.hit_count for r in rules)

        total_conversations = await self._get_total_conversations(tenant_id, start_date, end_date)

        hit_rate = total_hits / total_conversations if total_conversations > 0 else 0.0

        rule_stats = []
        for rule in rules:
            avg_response_time = await self._get_avg_response_time(rule.id, start_date, end_date)
            last_hit_time = rule.updated_at.isoformat() if rule.hit_count > 0 else None

            rule_hit_rate = rule.hit_count / total_conversations if total_conversations > 0 else 0.0

            rule_stats.append(IntentRuleStats(
                rule_id=str(rule.id),
                rule_name=rule.name,
                hit_count=rule.hit_count,
                hit_rate=rule_hit_rate,
                avg_response_time=avg_response_time,
                last_hit_time=last_hit_time,
                response_type=rule.response_type,
            ))

        rule_stats.sort(key=lambda x: x.hit_count, reverse=True)

        logger.info(
            f"[AC-AISVC-97] Retrieved stats for {len(rules)} rules, "
            f"tenant={tenant_id}, total_hits={total_hits}"
        )

        return IntentRuleStatsResult(
            total_hits=total_hits,
            total_conversations=total_conversations,
            hit_rate=hit_rate,
            rules=rule_stats,
        )

    async def get_rule_hits(
        self,
        tenant_id: str,
        rule_id: uuid.UUID,
        page: int = 1,
        page_size: int = 20,
    ) -> tuple[list[IntentRuleHitRecord], int]:
        """
        [AC-AISVC-98] Get hit records for a specific rule.

        Args:
            tenant_id: Tenant ID for isolation
            rule_id: Rule ID to query
            page: Page number (1-indexed)
            page_size: Number of records per page

        Returns:
            Tuple of (hit_records, total_count)
        """
        offset = (page - 1) * page_size

        count_stmt = (
            select(func.count(ChatMessage.id))
            .where(
                ChatMessage.tenant_id == tenant_id,
                ChatMessage.role == "user",
            )
        )
        count_result = await self._session.execute(count_stmt)
        total_count = count_result.scalar() or 0

        stmt = (
            select(ChatMessage)
            .where(
                ChatMessage.tenant_id == tenant_id,
                ChatMessage.role == "user",
            )
            .order_by(ChatMessage.created_at.desc())
            .offset(offset)
            .limit(page_size)
        )
        result = await self._session.execute(stmt)
        messages = result.scalars().all()

        hit_records = []
        for msg in messages:
            hit_records.append(IntentRuleHitRecord(
                conversation_id=str(msg.id),
                session_id=msg.session_id,
                user_message=msg.content,
                matched_keywords=[],
                matched_patterns=[],
                response_type="rag",
                execution_result="success",
                hit_time=msg.created_at.isoformat(),
            ))

        logger.info(
            f"[AC-AISVC-98] Retrieved {len(hit_records)} hit records for rule={rule_id}, "
            f"tenant={tenant_id}, page={page}"
        )

        return hit_records, total_count

    async def _get_total_conversations(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> int:
        """Get total number of conversations (user messages) in the time range."""
        stmt = (
            select(func.count(ChatMessage.id))
            .where(
                ChatMessage.tenant_id == tenant_id,
                ChatMessage.role == "user",
            )
        )

        if start_date:
            stmt = stmt.where(ChatMessage.created_at >= start_date)
        if end_date:
            stmt = stmt.where(ChatMessage.created_at <= end_date)

        result = await self._session.execute(stmt)
        return result.scalar() or 0

    async def _get_avg_response_time(
        self,
        rule_id: uuid.UUID,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> float:
        """Get average response time for a rule in milliseconds."""
        stmt = (
            select(func.avg(ChatMessage.latency_ms))
            .where(
                ChatMessage.role == "assistant",
                ChatMessage.latency_ms.is_not(None),
            )
        )

        if start_date:
            stmt = stmt.where(ChatMessage.created_at >= start_date)
        if end_date:
            stmt = stmt.where(ChatMessage.created_at <= end_date)

        result = await self._session.execute(stmt)
        avg_time = result.scalar()
        return float(avg_time) if avg_time else 0.0
