"""
Guardrail monitoring service for AI Service.
[AC-AISVC-106, AC-AISVC-107] Guardrail statistics and block records.
"""

import logging
import uuid
from dataclasses import dataclass
from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import col

from app.models.entities import ForbiddenWord

logger = logging.getLogger(__name__)


@dataclass
class WordStats:
    """Statistics for a single forbidden word."""

    wordId: str
    word: str
    category: str
    strategy: str
    hitCount: int
    blockCount: int
    lastHitAt: str | None

    def to_dict(self) -> dict[str, Any]:
        return {
            "wordId": self.wordId,
            "word": self.word,
            "category": self.category,
            "strategy": self.strategy,
            "hitCount": self.hitCount,
            "blockCount": self.blockCount,
            "lastHitAt": self.lastHitAt,
        }


@dataclass
class GuardrailBlockRecord:
    """A single block record for a forbidden word."""

    recordId: str
    sessionId: str
    originalText: str
    filteredText: str
    strategy: str
    blockedAt: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "recordId": self.recordId,
            "sessionId": self.sessionId,
            "originalText": self.originalText,
            "filteredText": self.filteredText,
            "strategy": self.strategy,
            "blockedAt": self.blockedAt,
        }


@dataclass
class GuardrailStatsResult:
    """Result of guardrail statistics query."""

    totalBlocks: int
    totalTriggers: int
    blockRate: float
    words: list[WordStats]
    categoryBreakdown: dict[str, int]

    def to_dict(self) -> dict[str, Any]:
        return {
            "totalBlocks": self.totalBlocks,
            "totalTriggers": self.totalTriggers,
            "blockRate": round(self.blockRate, 3),
            "words": [w.to_dict() for w in self.words],
            "categoryBreakdown": self.categoryBreakdown,
        }


class GuardrailMonitor:
    """
    [AC-AISVC-106, AC-AISVC-107] Guardrail monitoring service.

    Features:
    - Aggregate guardrail trigger statistics
    - Calculate block rates
    - Query block records for a specific word
    - Category breakdown analysis
    """

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

    async def get_guardrail_stats(
        self,
        tenant_id: str,
        category: str | None = None,
    ) -> GuardrailStatsResult:
        """
        [AC-AISVC-106] Get aggregated statistics for all guardrails.

        Args:
            tenant_id: Tenant ID for isolation
            category: Optional category filter

        Returns:
            GuardrailStatsResult with aggregated statistics
        """
        stmt = select(ForbiddenWord).where(
            ForbiddenWord.tenant_id == tenant_id,
            ForbiddenWord.is_enabled.is_(True),
        )

        if category:
            stmt = stmt.where(ForbiddenWord.category == category)

        stmt = stmt.order_by(col(ForbiddenWord.hit_count).desc())
        result = await self._session.execute(stmt)
        words = result.scalars().all()

        total_triggers = sum(w.hit_count for w in words)
        total_blocks = sum(
            w.hit_count for w in words
            if w.strategy == "block"
        )

        block_rate = total_blocks / total_triggers if total_triggers > 0 else 0.0

        word_stats: list[WordStats] = []
        category_breakdown: dict[str, int] = {}

        for word in words:
            block_count = word.hit_count if word.strategy == "block" else 0

            word_stats.append(
                WordStats(
                    wordId=str(word.id),
                    word=word.word,
                    category=word.category,
                    strategy=word.strategy,
                    hitCount=word.hit_count,
                    blockCount=block_count,
                    lastHitAt=word.updated_at.isoformat() if word.hit_count > 0 else None,
                )
            )

            if word.category in category_breakdown:
                category_breakdown[word.category] += word.hit_count
            else:
                category_breakdown[word.category] = word.hit_count

        for cat in ["competitor", "sensitive", "political", "custom"]:
            if cat not in category_breakdown:
                category_breakdown[cat] = 0

        logger.info(
            f"[AC-AISVC-106] Retrieved stats for {len(words)} words, "
            f"tenant={tenant_id}, total_triggers={total_triggers}"
        )

        return GuardrailStatsResult(
            totalBlocks=total_blocks,
            totalTriggers=total_triggers,
            blockRate=block_rate,
            words=word_stats,
            categoryBreakdown=category_breakdown,
        )

    async def get_word_blocks(
        self,
        tenant_id: str,
        word_id: uuid.UUID,
        page: int = 1,
        page_size: int = 20,
    ) -> tuple[list[GuardrailBlockRecord], int]:
        """
        [AC-AISVC-107] Get block records for a specific forbidden word.

        Note: This is a simplified implementation that returns mock data
        based on the word's hit count. In a production system, you would
        have a separate table to track individual block events.

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

        Returns:
            Tuple of (block_records, total_count)
        """
        word_stmt = select(ForbiddenWord).where(
            ForbiddenWord.tenant_id == tenant_id,
            ForbiddenWord.id == word_id,
        )
        word_result = await self._session.execute(word_stmt)
        word = word_result.scalar_one_or_none()

        if not word:
            return [], 0

        total_count = word.hit_count if word.strategy == "block" else 0

        records: list[GuardrailBlockRecord] = []

        if total_count > 0:
            offset = (page - 1) * page_size
            end_idx = min(offset + page_size, total_count)

            for i in range(offset, end_idx):
                records.append(
                    GuardrailBlockRecord(
                        recordId=f"block_{word_id}_{i + 1}",
                        sessionId=f"session_{i + 1}",
                        originalText=f"包含禁词 '{word.word}' 的文本样例",
                        filteredText=word.fallback_reply or "抱歉，让我换个方式回答您",
                        strategy=word.strategy,
                        blockedAt=word.updated_at.isoformat(),
                    )
                )

        logger.info(
            f"[AC-AISVC-107] Retrieved {len(records)} block records for word={word_id}, "
            f"tenant={tenant_id}, page={page}"
        )

        return records, total_count
