"""
Dashboard statistics service for AI Service.
[AC-AISVC-91, AC-AISVC-92] Enhanced dashboard statistics with monitoring metrics.
"""

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

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

from app.models.entities import (
    ChatMessage,
    FlowInstance,
    ForbiddenWord,
    IntentRule,
    PromptTemplate,
    PromptTemplateVersion,
)
from app.services.monitoring.cache import MonitoringCache

logger = logging.getLogger(__name__)


@dataclass
class TopItem:
    """Top N item for leaderboards."""

    id: str
    name: str
    count: int
    extra: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        result = {
            "id": self.id,
            "name": self.name,
            "count": self.count,
        }
        if self.extra:
            result.update(self.extra)
        return result


@dataclass
class EnhancedDashboardStats:
    """Enhanced dashboard statistics result."""

    intent_rule_hit_rate: float
    intent_rule_hit_count: int
    top_intent_rules: list[TopItem]

    prompt_template_usage_count: int
    top_prompt_templates: list[TopItem]

    script_flow_activation_count: int
    script_flow_completion_rate: float
    top_script_flows: list[TopItem]

    guardrail_block_count: int
    guardrail_block_rate: float
    top_guardrail_words: list[TopItem]

    def to_dict(self) -> dict[str, Any]:
        return {
            "intentRuleHitRate": self.intent_rule_hit_rate,
            "intentRuleHitCount": self.intent_rule_hit_count,
            "topIntentRules": [r.to_dict() for r in self.top_intent_rules],
            "promptTemplateUsageCount": self.prompt_template_usage_count,
            "topPromptTemplates": [t.to_dict() for t in self.top_prompt_templates],
            "scriptFlowActivationCount": self.script_flow_activation_count,
            "scriptFlowCompletionRate": self.script_flow_completion_rate,
            "topScriptFlows": [f.to_dict() for f in self.top_script_flows],
            "guardrailBlockCount": self.guardrail_block_count,
            "guardrailBlockRate": self.guardrail_block_rate,
            "topGuardrailWords": [w.to_dict() for w in self.top_guardrail_words],
        }


class DashboardService:
    """
    [AC-AISVC-91, AC-AISVC-92] Dashboard statistics service.

    Features:
    - Intent rule hit statistics
    - Prompt template usage statistics
    - Script flow activation statistics
    - Guardrail block statistics
    - Redis caching for performance
    """

    def __init__(
        self,
        session: AsyncSession,
        cache: MonitoringCache | None = None,
    ):
        self._session = session
        self._cache = cache

    async def get_enhanced_stats(
        self,
        tenant_id: str,
        start_date: datetime | None = None,
        end_date: datetime | None = None,
        use_cache: bool = True,
    ) -> EnhancedDashboardStats:
        """
        [AC-AISVC-91, AC-AISVC-92] Get enhanced dashboard statistics.

        Args:
            tenant_id: Tenant ID for isolation
            start_date: Optional start date filter
            end_date: Optional end date filter
            use_cache: Whether to use Redis cache

        Returns:
            EnhancedDashboardStats with all statistics
        """
        if use_cache and self._cache:
            cached = await self._cache.get_dashboard_stats(tenant_id)
            if cached:
                logger.info(f"[AC-AISVC-91] Returning cached dashboard stats for tenant={tenant_id}")
                return self._dict_to_stats(cached)

        stats = await self._aggregate_from_db(tenant_id, start_date, end_date)

        if use_cache and self._cache:
            await self._cache.set_dashboard_stats(tenant_id, stats.to_dict())

        logger.info(
            f"[AC-AISVC-91] Computed dashboard stats for tenant={tenant_id}, "
            f"intent_hits={stats.intent_rule_hit_count}, "
            f"template_usage={stats.prompt_template_usage_count}"
        )

        return stats

    async def _aggregate_from_db(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> EnhancedDashboardStats:
        """Aggregate statistics from database."""

        intent_stats = await self._get_intent_rule_stats(tenant_id, start_date, end_date)
        template_stats = await self._get_template_stats(tenant_id, start_date, end_date)
        flow_stats = await self._get_flow_stats(tenant_id, start_date, end_date)
        guardrail_stats = await self._get_guardrail_stats(tenant_id, start_date, end_date)

        return EnhancedDashboardStats(
            intent_rule_hit_rate=intent_stats["hit_rate"],
            intent_rule_hit_count=intent_stats["hit_count"],
            top_intent_rules=intent_stats["top_rules"],
            prompt_template_usage_count=template_stats["usage_count"],
            top_prompt_templates=template_stats["top_templates"],
            script_flow_activation_count=flow_stats["activation_count"],
            script_flow_completion_rate=flow_stats["completion_rate"],
            top_script_flows=flow_stats["top_flows"],
            guardrail_block_count=guardrail_stats["block_count"],
            guardrail_block_rate=guardrail_stats["block_rate"],
            top_guardrail_words=guardrail_stats["top_words"],
        )

    async def _get_intent_rule_stats(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> dict[str, Any]:
        """Get intent rule statistics."""

        rules_stmt = select(IntentRule).where(
            IntentRule.tenant_id == tenant_id,
            IntentRule.is_enabled == True,
        )
        result = await self._session.execute(rules_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

        sorted_rules = sorted(rules, key=lambda r: r.hit_count, reverse=True)[:5]
        top_rules = [
            TopItem(
                id=str(r.id),
                name=r.name,
                count=r.hit_count,
                extra={"responseType": r.response_type},
            )
            for r in sorted_rules
        ]

        return {
            "hit_count": total_hits,
            "hit_rate": hit_rate,
            "top_rules": top_rules,
        }

    async def _get_template_stats(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> dict[str, Any]:
        """Get prompt template usage statistics."""

        usage_stmt = (
            select(
                ChatMessage.prompt_template_id,
                func.count(ChatMessage.id).label("usage_count"),
            )
            .where(
                ChatMessage.tenant_id == tenant_id,
                ChatMessage.prompt_template_id.is_not(None),
                ChatMessage.role == "assistant",
            )
            .group_by(ChatMessage.prompt_template_id)
            .order_by(desc("usage_count"))
        )

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

        result = await self._session.execute(usage_stmt)
        usage_rows = result.fetchall()

        total_usage = sum(row.usage_count for row in usage_rows)

        top_templates = []
        for row in usage_rows[:5]:
            template = await self._get_template_name(row.prompt_template_id)
            top_templates.append(TopItem(
                id=str(row.prompt_template_id),
                name=template,
                count=row.usage_count,
            ))

        return {
            "usage_count": total_usage,
            "top_templates": top_templates,
        }

    async def _get_template_name(self, template_id: uuid.UUID) -> str:
        """Get template name by ID."""
        stmt = select(PromptTemplate.name).where(PromptTemplate.id == template_id)
        result = await self._session.execute(stmt)
        name = result.scalar_one_or_none()
        return name or "Unknown Template"

    async def _get_flow_stats(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> dict[str, Any]:
        """Get script flow activation statistics."""

        flow_stmt = (
            select(
                FlowInstance.flow_id,
                func.count(FlowInstance.id).label("activation_count"),
                func.sum(
                    func.case(
                        (FlowInstance.status == "completed", 1),
                        else_=0,
                    )
                ).label("completion_count"),
            )
            .where(FlowInstance.tenant_id == tenant_id)
            .group_by(FlowInstance.flow_id)
            .order_by(desc("activation_count"))
        )

        if start_date:
            flow_stmt = flow_stmt.where(FlowInstance.started_at >= start_date)
        if end_date:
            flow_stmt = flow_stmt.where(FlowInstance.started_at <= end_date)

        result = await self._session.execute(flow_stmt)
        flow_rows = result.fetchall()

        total_activation = sum(row.activation_count for row in flow_rows)
        total_completion = sum(row.completion_count or 0 for row in flow_rows)
        completion_rate = total_completion / total_activation if total_activation > 0 else 0.0

        top_flows = []
        for row in flow_rows[:5]:
            flow_name = await self._get_flow_name(row.flow_id)
            top_flows.append(TopItem(
                id=str(row.flow_id),
                name=flow_name,
                count=row.activation_count,
                extra={
                    "completionCount": row.completion_count or 0,
                },
            ))

        return {
            "activation_count": total_activation,
            "completion_rate": completion_rate,
            "top_flows": top_flows,
        }

    async def _get_flow_name(self, flow_id: uuid.UUID) -> str:
        """Get flow name by ID."""
        from app.models.entities import ScriptFlow
        stmt = select(ScriptFlow.name).where(ScriptFlow.id == flow_id)
        result = await self._session.execute(stmt)
        name = result.scalar_one_or_none()
        return name or "Unknown Flow"

    async def _get_guardrail_stats(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> dict[str, Any]:
        """Get guardrail block statistics."""

        words_stmt = select(ForbiddenWord).where(
            ForbiddenWord.tenant_id == tenant_id,
            ForbiddenWord.is_enabled == True,
        )
        result = await self._session.execute(words_stmt)
        words = result.scalars().all()

        total_blocks = sum(w.hit_count for w in words)

        total_outputs = await self._get_total_outputs(tenant_id, start_date, end_date)
        block_rate = total_blocks / total_outputs if total_outputs > 0 else 0.0

        sorted_words = sorted(words, key=lambda w: w.hit_count, reverse=True)[:5]
        top_words = [
            TopItem(
                id=str(w.id),
                name=w.word,
                count=w.hit_count,
                extra={
                    "category": w.category,
                    "strategy": w.strategy,
                },
            )
            for w in sorted_words
        ]

        return {
            "block_count": total_blocks,
            "block_rate": block_rate,
            "top_words": top_words,
        }

    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)."""
        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_total_outputs(
        self,
        tenant_id: str,
        start_date: datetime | None,
        end_date: datetime | None,
    ) -> int:
        """Get total number of AI outputs (assistant messages)."""
        stmt = (
            select(func.count(ChatMessage.id))
            .where(
                ChatMessage.tenant_id == tenant_id,
                ChatMessage.role == "assistant",
            )
        )

        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

    def _dict_to_stats(self, data: dict[str, Any]) -> EnhancedDashboardStats:
        """Convert dict to EnhancedDashboardStats."""
        return EnhancedDashboardStats(
            intent_rule_hit_rate=data.get("intentRuleHitRate", 0.0),
            intent_rule_hit_count=data.get("intentRuleHitCount", 0),
            top_intent_rules=[
                TopItem(
                    id=r["id"],
                    name=r["name"],
                    count=r["count"],
                    extra=r.get("extra", {}),
                )
                for r in data.get("topIntentRules", [])
            ],
            prompt_template_usage_count=data.get("promptTemplateUsageCount", 0),
            top_prompt_templates=[
                TopItem(
                    id=t["id"],
                    name=t["name"],
                    count=t["count"],
                )
                for t in data.get("topPromptTemplates", [])
            ],
            script_flow_activation_count=data.get("scriptFlowActivationCount", 0),
            script_flow_completion_rate=data.get("scriptFlowCompletionRate", 0.0),
            top_script_flows=[
                TopItem(
                    id=f["id"],
                    name=f["name"],
                    count=f["count"],
                    extra=f.get("extra", {}),
                )
                for f in data.get("topScriptFlows", [])
            ],
            guardrail_block_count=data.get("guardrailBlockCount", 0),
            guardrail_block_rate=data.get("guardrailBlockRate", 0.0),
            top_guardrail_words=[
                TopItem(
                    id=w["id"],
                    name=w["name"],
                    count=w["count"],
                    extra=w.get("extra", {}),
                )
                for w in data.get("topGuardrailWords", [])
            ],
        )
