"""
Device management service with CRUD operations and device monitoring
"""
import logging
from typing import List, Optional, Dict, Any
from datetime import datetime, timedelta
from sqlalchemy.orm import Session, joinedload 
from sqlalchemy import desc, func, and_
from app.models import Device, LogEntry, FileUpload, InventoryGroup
from config.database_config import get_db

class DeviceService:
    """Service for managing devices and device-related operations"""
    
    def __init__(self):
        self._db = None
        self.logger = logging.getLogger(__name__)

    @property
    def db(self):
        """Lazily resolve the database handle (see LogCompressionService.db)."""
        if self._db is None:
            self._db = get_db()
        return self._db
    
    # Basic CRUD Operations

    def create_device(self, hostname: str, device_ip: str, nume_masa: str, **kwargs) -> Device:
        """Create a new device"""
        try:
            with self.db.get_session() as session:
                # Check if device already exists
                existing = session.query(Device).filter(
                    (Device.hostname == hostname) | (Device.device_ip == device_ip)
                ).first()
                
                if existing:
                    raise ValueError(f"Device with hostname '{hostname}' or IP '{device_ip}' already exists")
                
                device = Device(
                    hostname=hostname,
                    device_ip=device_ip,
                    nume_masa=nume_masa,
                    device_type=kwargs.get('device_type', 'unknown'),
                    os_version=kwargs.get('os_version'),
                    status=kwargs.get('status', 'active'),
                    location=kwargs.get('location'),
                    description=kwargs.get('description'),
                    last_seen=datetime.utcnow()
                )
                
                session.add(device)
                session.commit()
                session.refresh(device)
                
                self.logger.info(f"Created device: {hostname} ({device_ip})")
                return device
                
        except Exception as e:
            self.logger.error(f"Error creating device: {e}")
            raise

    def get_device_by_id(self, device_id: int) -> Optional[Device]:
        """Get device by ID with relationships loaded"""
        try:
            with self.db.get_session() as session:
                return session.query(Device).options(
                    joinedload(Device.logs),
                    joinedload(Device.files),
                    joinedload(Device.inventory_groups)
                ).filter(Device.id == device_id).first()
        except Exception as e:
            self.logger.error(f"Error getting device {device_id}: {e}")
            return None

    def get_device_by_hostname(self, hostname: str) -> Optional[Device]:
        """Get device by hostname"""
        try:
            with self.db.get_session() as session:
                return session.query(Device).filter(Device.hostname == hostname).first()
        except Exception as e:
            self.logger.error(f"Error getting device by hostname {hostname}: {e}")
            return None

    def get_device_by_ip(self, device_ip: str) -> Optional[Device]:
        """Get device by IP address"""
        try:
            with self.db.get_session() as session:
                return session.query(Device).filter(Device.device_ip == device_ip).first()
        except Exception as e:
            self.logger.error(f"Error getting device by IP {device_ip}: {e}")
            return None

    def get_all_devices(self, status: Optional[str] = None, limit: Optional[int] = None) -> List[Device]:
        """Get all devices with optional filtering"""
        try:
            with self.db.get_session() as session:
                query = session.query(Device).order_by(desc(Device.last_seen))
                
                if status:
                    query = query.filter(Device.status == status)
                
                if limit:
                    query = query.limit(limit)
                
                return query.all()
        except Exception as e:
            self.logger.error(f"Error getting devices: {e}")
            return []

    def update_device(self, device_id: int, **kwargs) -> Optional[Device]:
        """Update device information"""
        try:
            with self.db.get_session() as session:
                device = session.query(Device).filter(Device.id == device_id).first()
                if not device:
                    return None
                
                # Update allowed fields
                allowed_fields = [
                    'hostname', 'device_ip', 'nume_masa', 'device_type', 
                    'os_version', 'status', 'location', 'description'
                ]
                
                for field, value in kwargs.items():
                    if field in allowed_fields and hasattr(device, field):
                        setattr(device, field, value)
                
                session.commit()
                session.refresh(device)
                
                self.logger.info(f"Updated device {device_id}")
                return device
                
        except Exception as e:
            self.logger.error(f"Error updating device {device_id}: {e}")
            raise

    def delete_device(self, device_id: int) -> bool:
        """Delete device (soft delete by setting status to inactive)"""
        try:
            with self.db.get_session() as session:
                device = session.query(Device).filter(Device.id == device_id).first()
                if not device:
                    return False
                
                # Soft delete - set status to inactive
                device.status = 'inactive'
                session.commit()
                
                self.logger.info(f"Soft deleted device {device_id}")
                return True
                
        except Exception as e:
            self.logger.error(f"Error deleting device {device_id}: {e}")
            return False

    # Device Monitoring Functions

    def update_device_last_seen(self, hostname: str = None, device_ip: str = None) -> Optional[Device]:
        """Update device last seen timestamp"""
        try:
            with self.db.get_session() as session:
                device = None
                
                if hostname:
                    device = session.query(Device).filter(Device.hostname == hostname).first()
                elif device_ip:
                    device = session.query(Device).filter(Device.device_ip == device_ip).first()
                
                if device:
                    device.last_seen = datetime.utcnow()
                    session.commit()
                
                return device
                
        except Exception as e:
            self.logger.error(f"Error updating last seen: {e}")
            return None

    def get_device_statistics(self, device_id: int) -> Dict[str, Any]:
        """Get comprehensive statistics for a device"""
        try:
            with self.db.get_session() as session:
                device = session.query(Device).filter(Device.id == device_id).first()
                if not device:
                    return {}
                
                # Log statistics
                total_logs = session.query(LogEntry).filter(LogEntry.device_id == device_id).count()
                
                # Logs by severity
                severity_counts = session.query(
                    LogEntry.severity,
                    func.count(LogEntry.id)
                ).filter(
                    LogEntry.device_id == device_id
                ).group_by(LogEntry.severity).all()
                
                # Recent activity (last 24 hours)
                last_24h = datetime.utcnow() - timedelta(hours=24)
                recent_logs = session.query(LogEntry).filter(
                    and_(LogEntry.device_id == device_id, LogEntry.timestamp >= last_24h)
                ).count()
                
                # File uploads
                total_files = session.query(FileUpload).filter(
                    FileUpload.device_id == device_id
                ).count()
                
                # Last log
                last_log = session.query(LogEntry).filter(
                    LogEntry.device_id == device_id
                ).order_by(desc(LogEntry.timestamp)).first()
                
                return {
                    'device': device,
                    'total_logs': total_logs,
                    'severity_counts': dict(severity_counts),
                    'recent_logs_24h': recent_logs,
                    'total_files': total_files,
                    'last_log': last_log,
                    # Days since the device was last seen (0 = seen today / currently active).
                    # Previously mislabeled as "uptime_days" which implied the opposite.
                    'days_since_last_seen': (datetime.utcnow() - device.last_seen).days if device.last_seen else None,
                    'is_online': device.is_online,
                }
                
        except Exception as e:
            self.logger.error(f"Error getting device statistics: {e}")
            return {}

    def get_inactive_devices(self, hours: int = 24) -> List[Device]:
        """Get devices that haven't been seen recently"""
        try:
            with self.db.get_session() as session:
                cutoff_time = datetime.utcnow() - timedelta(hours=hours)
                
                return session.query(Device).filter(
                    and_(
                        Device.last_seen < cutoff_time,
                        Device.status.in_(['active', 'maintenance'])
                    )
                ).order_by(desc(Device.last_seen)).all()
                
        except Exception as e:
            self.logger.error(f"Error getting inactive devices: {e}")
            return []

    def get_device_logs(self, device_id: int, limit: int = 100, severity: str = None) -> List[LogEntry]:
        """Get logs for a specific device"""
        try:
            with self.db.get_session() as session:
                query = session.query(LogEntry).filter(
                    LogEntry.device_id == device_id
                ).order_by(desc(LogEntry.timestamp))
                
                if severity:
                    query = query.filter(LogEntry.severity == severity)
                
                return query.limit(limit).all()
                
        except Exception as e:
            self.logger.error(f"Error getting device logs: {e}")
            return []

    def search_devices(self, search_term: str) -> List[Device]:
        """Search devices by hostname, IP, or description"""
        try:
            with self.db.get_session() as session:
                search_pattern = f"%{search_term}%"
                
                return session.query(Device).filter(
                    (Device.hostname.like(search_pattern)) |
                    (Device.device_ip.like(search_pattern)) |
                    (Device.nume_masa.like(search_pattern)) |
                    (Device.location.like(search_pattern)) |
                    (Device.description.like(search_pattern))
                ).order_by(desc(Device.last_seen)).all()
                
        except Exception as e:
            self.logger.error(f"Error searching devices: {e}")
            return []

    # Bulk Operations

    def bulk_update_status(self, device_ids: List[int], status: str) -> int:
        """Update status for multiple devices"""
        try:
            with self.db.get_session() as session:
                updated = session.query(Device).filter(
                    Device.id.in_(device_ids)
                ).update({Device.status: status}, synchronize_session=False)
                
                session.commit()
                self.logger.info(f"Updated status for {updated} devices")
                return updated
                
        except Exception as e:
            self.logger.error(f"Error bulk updating status: {e}")
            return 0

    def get_device_summary(self) -> Dict[str, Any]:
        """Get summary statistics for all devices"""
        try:
            with self.db.get_session() as session:
                # Device status counts
                status_counts = session.query(
                    Device.status,
                    func.count(Device.id)
                ).group_by(Device.status).all()
                
                # Device type counts
                type_counts = session.query(
                    Device.device_type,
                    func.count(Device.id)
                ).group_by(Device.device_type).all()
                
                # Recent activity
                last_24h = datetime.utcnow() - timedelta(hours=24)
                devices_seen_24h = session.query(Device).filter(
                    Device.last_seen >= last_24h
                ).count()
                
                return {
                    'total_devices': session.query(Device).count(),
                    'status_counts': dict(status_counts),
                    'type_counts': dict(type_counts),
                    'devices_seen_24h': devices_seen_24h
                }
                
        except Exception as e:
            self.logger.error(f"Error getting device summary: {e}")
            return {}