# services/alert_processor/app/repositories/alerts_repository.py
"""
Alerts Repository - Database access layer for alerts
"""

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_, or_
from typing import List, Dict, Any, Optional
from uuid import UUID
import structlog

from app.models.alerts import Alert, AlertStatus, AlertSeverity

logger = structlog.get_logger()


class AlertsRepository:
    """Repository for alert database operations"""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_alerts(
        self,
        tenant_id: UUID,
        severity: Optional[str] = None,
        status: Optional[str] = None,
        resolved: Optional[bool] = None,
        limit: int = 100,
        offset: int = 0
    ) -> List[Alert]:
        """
        Get alerts with optional filters

        Args:
            tenant_id: Tenant UUID
            severity: Filter by severity (low, medium, high, urgent)
            status: Filter by status (active, resolved, acknowledged, ignored)
            resolved: Filter by resolved status (True = resolved, False = not resolved, None = all)
            limit: Maximum number of results
            offset: Pagination offset

        Returns:
            List of Alert objects
        """
        try:
            query = select(Alert).where(Alert.tenant_id == tenant_id)

            # Apply filters
            if severity:
                query = query.where(Alert.severity == severity)

            if status:
                query = query.where(Alert.status == status)

            if resolved is not None:
                if resolved:
                    query = query.where(Alert.status == AlertStatus.RESOLVED.value)
                else:
                    query = query.where(Alert.status != AlertStatus.RESOLVED.value)

            # Order by created_at descending (newest first)
            query = query.order_by(Alert.created_at.desc())

            # Apply pagination
            query = query.limit(limit).offset(offset)

            result = await self.db.execute(query)
            alerts = result.scalars().all()

            logger.info(
                "Retrieved alerts",
                tenant_id=str(tenant_id),
                count=len(alerts),
                filters={"severity": severity, "status": status, "resolved": resolved}
            )

            return list(alerts)

        except Exception as e:
            logger.error("Error retrieving alerts", error=str(e), tenant_id=str(tenant_id))
            raise

    async def get_alerts_summary(self, tenant_id: UUID) -> Dict[str, Any]:
        """
        Get summary of alerts by severity and status

        Args:
            tenant_id: Tenant UUID

        Returns:
            Dict with counts by severity and status
        """
        try:
            # Count by severity
            severity_query = (
                select(
                    Alert.severity,
                    func.count(Alert.id).label("count")
                )
                .where(
                    and_(
                        Alert.tenant_id == tenant_id,
                        Alert.status != AlertStatus.RESOLVED.value
                    )
                )
                .group_by(Alert.severity)
            )

            severity_result = await self.db.execute(severity_query)
            severity_counts = {row[0]: row[1] for row in severity_result.all()}

            # Count by status
            status_query = (
                select(
                    Alert.status,
                    func.count(Alert.id).label("count")
                )
                .where(Alert.tenant_id == tenant_id)
                .group_by(Alert.status)
            )

            status_result = await self.db.execute(status_query)
            status_counts = {row[0]: row[1] for row in status_result.all()}

            # Count active alerts (not resolved)
            active_count = sum(
                count for status, count in status_counts.items()
                if status != AlertStatus.RESOLVED.value
            )

            # Map to expected field names (dashboard expects "critical")
            summary = {
                "total_count": sum(status_counts.values()),
                "active_count": active_count,
                "critical_count": severity_counts.get(AlertSeverity.URGENT.value, 0),  # Map URGENT to critical
                "high_count": severity_counts.get(AlertSeverity.HIGH.value, 0),
                "medium_count": severity_counts.get(AlertSeverity.MEDIUM.value, 0),
                "low_count": severity_counts.get(AlertSeverity.LOW.value, 0),
                "resolved_count": status_counts.get(AlertStatus.RESOLVED.value, 0),
                "acknowledged_count": status_counts.get(AlertStatus.ACKNOWLEDGED.value, 0),
            }

            logger.info(
                "Retrieved alerts summary",
                tenant_id=str(tenant_id),
                summary=summary
            )

            return summary

        except Exception as e:
            logger.error("Error retrieving alerts summary", error=str(e), tenant_id=str(tenant_id))
            raise

    async def get_alert_by_id(self, tenant_id: UUID, alert_id: UUID) -> Optional[Alert]:
        """Get a specific alert by ID"""
        try:
            query = select(Alert).where(
                and_(
                    Alert.tenant_id == tenant_id,
                    Alert.id == alert_id
                )
            )

            result = await self.db.execute(query)
            alert = result.scalar_one_or_none()

            if alert:
                logger.info("Retrieved alert", alert_id=str(alert_id), tenant_id=str(tenant_id))
            else:
                logger.warning("Alert not found", alert_id=str(alert_id), tenant_id=str(tenant_id))

            return alert

        except Exception as e:
            logger.error("Error retrieving alert", error=str(e), alert_id=str(alert_id))
            raise
