from sqlalchemy.orm import Session
from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta
from ..models.security_event import SecurityEvent, SecurityEventType, SecurityEventSeverity
from ...auth.models.user import User
from ...shared.config.logging_config import get_logger

logger = get_logger(__name__)

class SecurityMonitoringService:
    """Service for monitoring and analyzing security events"""
    
    @staticmethod
    def log_security_event(
        db: Session,
        event_type: SecurityEventType,
        severity: SecurityEventSeverity,
        user_id: Optional[int] = None,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None,
        request_path: Optional[str] = None,
        request_method: Optional[str] = None,
        request_id: Optional[str] = None,
        description: Optional[str] = None,
        details: Optional[Dict[str, Any]] = None
    ) -> SecurityEvent:
        """Log a security event"""
        try:
            event = SecurityEvent(
                user_id=user_id,
                event_type=event_type,
                severity=severity,
                ip_address=ip_address,
                user_agent=user_agent,
                request_path=request_path,
                request_method=request_method,
                request_id=request_id,
                description=description,
                details=details
            )
            db.add(event)
            db.commit()
            db.refresh(event)
            
            # Check for suspicious patterns
            SecurityMonitoringService._check_suspicious_patterns(db, event)
            
            return event
        except Exception as e:
            logger.error(f"Error logging security event: {str(e)}")
            db.rollback()
            raise
    
    @staticmethod
    def _check_suspicious_patterns(db: Session, event: SecurityEvent):
        """Check for suspicious activity patterns"""
        # Multiple failed login attempts from same IP
        if event.event_type == SecurityEventType.login_failure:
            recent_failures = db.query(SecurityEvent).filter(
                SecurityEvent.event_type == SecurityEventType.login_failure,
                SecurityEvent.ip_address == event.ip_address,
                SecurityEvent.created_at >= datetime.utcnow() - timedelta(minutes=15)
            ).count()
            
            if recent_failures >= 5:
                # Log suspicious activity
                SecurityMonitoringService.log_security_event(
                    db,
                    SecurityEventType.suspicious_activity,
                    SecurityEventSeverity.high,
                    ip_address=event.ip_address,
                    description=f"Multiple failed login attempts ({recent_failures}) from IP {event.ip_address}",
                    details={"failure_count": recent_failures}
                )
        
        # Multiple permission denied from same user
        if event.event_type == SecurityEventType.permission_denied and event.user_id:
            recent_denials = db.query(SecurityEvent).filter(
                SecurityEvent.event_type == SecurityEventType.permission_denied,
                SecurityEvent.user_id == event.user_id,
                SecurityEvent.created_at >= datetime.utcnow() - timedelta(hours=1)
            ).count()
            
            if recent_denials >= 10:
                SecurityMonitoringService.log_security_event(
                    db,
                    SecurityEventType.suspicious_activity,
                    SecurityEventSeverity.medium,
                    user_id=event.user_id,
                    description=f"User {event.user_id} has {recent_denials} permission denials in the last hour",
                    details={"denial_count": recent_denials}
                )
    
    @staticmethod
    def get_security_events(
        db: Session,
        user_id: Optional[int] = None,
        event_type: Optional[SecurityEventType] = None,
        severity: Optional[SecurityEventSeverity] = None,
        ip_address: Optional[str] = None,
        resolved: Optional[bool] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None,
        limit: int = 100,
        offset: int = 0
    ) -> List[SecurityEvent]:
        """Get security events with filters"""
        query = db.query(SecurityEvent)
        
        if user_id:
            query = query.filter(SecurityEvent.user_id == user_id)
        if event_type:
            query = query.filter(SecurityEvent.event_type == event_type)
        if severity:
            query = query.filter(SecurityEvent.severity == severity)
        if ip_address:
            query = query.filter(SecurityEvent.ip_address == ip_address)
        if resolved is not None:
            query = query.filter(SecurityEvent.resolved == resolved)
        if start_date:
            query = query.filter(SecurityEvent.created_at >= start_date)
        if end_date:
            query = query.filter(SecurityEvent.created_at <= end_date)
        
        return query.order_by(SecurityEvent.created_at.desc()).offset(offset).limit(limit).all()
    
    @staticmethod
    def get_security_stats(
        db: Session,
        days: int = 7
    ) -> Dict[str, Any]:
        """Get security statistics for the last N days"""
        start_date = datetime.utcnow() - timedelta(days=days)
        
        total_events = db.query(SecurityEvent).filter(
            SecurityEvent.created_at >= start_date
        ).count()
        
        by_type = {}
        by_severity = {}
        
        events = db.query(SecurityEvent).filter(
            SecurityEvent.created_at >= start_date
        ).all()
        
        for event in events:
            event_type = event.event_type.value
            severity = event.severity.value
            
            by_type[event_type] = by_type.get(event_type, 0) + 1
            by_severity[severity] = by_severity.get(severity, 0) + 1
        
        unresolved_critical = db.query(SecurityEvent).filter(
            SecurityEvent.severity == SecurityEventSeverity.critical,
            SecurityEvent.resolved == False,
            SecurityEvent.created_at >= start_date
        ).count()
        
        return {
            "total_events": total_events,
            "by_type": by_type,
            "by_severity": by_severity,
            "unresolved_critical": unresolved_critical,
            "period_days": days
        }
    
    @staticmethod
    def resolve_event(
        db: Session,
        event_id: int,
        resolved_by: int,
        resolution_notes: Optional[str] = None
    ) -> SecurityEvent:
        """Mark a security event as resolved"""
        event = db.query(SecurityEvent).filter(SecurityEvent.id == event_id).first()
        if not event:
            raise ValueError("Security event not found")
        
        event.resolved = True
        event.resolved_at = datetime.utcnow()
        event.resolved_by = resolved_by
        event.resolution_notes = resolution_notes
        
        db.commit()
        db.refresh(event)
        return event

security_monitoring_service = SecurityMonitoringService()

