from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta
from .base import BaseRepository
from ..models import License, LicenseToken, ActivationEvent, EventType
import logging

logger = logging.getLogger(__name__)

class LicenseRepository(BaseRepository):
    """Repository for license-related database operations"""
    
    def get_license_by_key(self, license_key: str) -> Optional[Dict[str, Any]]:
        """Get license by key"""
        query = """
            SELECT l.*, c.name as customer_name, c.email as customer_email
            FROM licenses l
            JOIN customers c ON l.customer_id = c.id
            WHERE l.license_key = %s
        """
        return self.execute_one(query, (license_key,))
    
    def get_license_by_id(self, license_id: str) -> Optional[Dict[str, Any]]:
        """Get license by ID"""
        query = """
            SELECT l.*, c.name as customer_name, c.email as customer_email
            FROM licenses l
            JOIN customers c ON l.customer_id = c.id
            WHERE l.id = %s
        """
        return self.execute_one(query, (license_id,))
    
    def get_active_devices(self, license_id: str) -> List[Dict[str, Any]]:
        """Get active devices for a license"""
        query = """
            SELECT DISTINCT ON (hardware_id) 
                hardware_id,
                ip_address,
                user_agent,
                app_version,
                timestamp as last_seen
            FROM license_heartbeats
            WHERE license_id = %s
                AND timestamp > NOW() - INTERVAL '15 minutes'
            ORDER BY hardware_id, timestamp DESC
        """
        return self.execute_query(query, (license_id,))
    
    def get_device_count(self, license_id: str) -> int:
        """Get count of active devices"""
        query = """
            SELECT COUNT(DISTINCT hardware_id) as device_count
            FROM license_heartbeats
            WHERE license_id = %s
                AND timestamp > NOW() - INTERVAL '15 minutes'
        """
        result = self.execute_one(query, (license_id,))
        return result['device_count'] if result else 0
    
    def create_license_token(self, license_id: str, hardware_id: str, 
                           valid_hours: int = 24) -> Optional[str]:
        """Create offline validation token"""
        import secrets
        token = secrets.token_urlsafe(64)
        valid_until = datetime.utcnow() + timedelta(hours=valid_hours)
        
        query = """
            INSERT INTO license_tokens (license_id, token, hardware_id, valid_until)
            VALUES (%s, %s, %s, %s)
            RETURNING id
        """
        
        result = self.execute_insert(query, (license_id, token, hardware_id, valid_until))
        return token if result else None
    
    def validate_token(self, token: str) -> Optional[Dict[str, Any]]:
        """Validate offline token"""
        query = """
            SELECT lt.*, l.license_key, l.is_active, l.expires_at
            FROM license_tokens lt
            JOIN licenses l ON lt.license_id = l.id
            WHERE lt.token = %s
                AND lt.valid_until > NOW()
                AND l.is_active = true
        """
        
        result = self.execute_one(query, (token,))
        
        if result:
            # Update validation count and timestamp
            update_query = """
                UPDATE license_tokens 
                SET validation_count = validation_count + 1,
                    last_validated = NOW()
                WHERE token = %s
            """
            self.execute_update(update_query, (token,))
        
        return result
    
    def record_heartbeat(self, license_id: str, hardware_id: str, 
                        ip_address: str = None, user_agent: str = None,
                        app_version: str = None, session_data: Dict = None) -> None:
        """Record license heartbeat"""
        query = """
            INSERT INTO license_heartbeats 
                (license_id, hardware_id, ip_address, user_agent, app_version, session_data)
            VALUES (%s, %s, %s, %s, %s, %s)
        """
        
        import json
        session_json = json.dumps(session_data) if session_data else None
        
        self.execute_insert(query, (
            license_id, hardware_id, ip_address, 
            user_agent, app_version, session_json
        ))
    
    def record_activation_event(self, license_id: str, event_type: EventType,
                               hardware_id: str = None, previous_hardware_id: str = None,
                               ip_address: str = None, user_agent: str = None,
                               success: bool = True, error_message: str = None,
                               metadata: Dict = None) -> str:
        """Record activation event"""
        query = """
            INSERT INTO activation_events 
                (license_id, event_type, hardware_id, previous_hardware_id,
                 ip_address, user_agent, success, error_message, metadata)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
            RETURNING id
        """
        
        import json
        metadata_json = json.dumps(metadata) if metadata else None
        
        return self.execute_insert(query, (
            license_id, event_type.value, hardware_id, previous_hardware_id,
            ip_address, user_agent, success, error_message, metadata_json
        ))
    
    def get_recent_activations(self, license_id: str, hours: int = 24) -> List[Dict[str, Any]]:
        """Get recent activation events"""
        query = """
            SELECT * FROM activation_events
            WHERE license_id = %s
                AND created_at > NOW() - INTERVAL '%s hours'
            ORDER BY created_at DESC
        """
        return self.execute_query(query, (license_id, hours))
    
    def check_hardware_id_exists(self, license_id: str, hardware_id: str) -> bool:
        """Check if hardware ID is already registered"""
        query = """
            SELECT 1 FROM activation_events
            WHERE license_id = %s
                AND hardware_id = %s
                AND event_type IN ('activation', 'reactivation')
                AND success = true
            LIMIT 1
        """
        result = self.execute_one(query, (license_id, hardware_id))
        return result is not None
    
    def deactivate_device(self, license_id: str, hardware_id: str) -> bool:
        """Deactivate a device"""
        # Record deactivation event
        self.record_activation_event(
            license_id=license_id,
            event_type=EventType.DEACTIVATION,
            hardware_id=hardware_id,
            success=True
        )
        
        # Remove any active tokens for this device
        query = """
            DELETE FROM license_tokens
            WHERE license_id = %s AND hardware_id = %s
        """
        affected = self.execute_delete(query, (license_id, hardware_id))
        
        return affected > 0
    
    def transfer_license(self, license_id: str, from_hardware_id: str, 
                        to_hardware_id: str, ip_address: str = None) -> bool:
        """Transfer license from one device to another"""
        try:
            # Deactivate old device
            self.deactivate_device(license_id, from_hardware_id)
            
            # Record transfer event
            self.record_activation_event(
                license_id=license_id,
                event_type=EventType.TRANSFER,
                hardware_id=to_hardware_id,
                previous_hardware_id=from_hardware_id,
                ip_address=ip_address,
                success=True
            )
            
            return True
            
        except Exception as e:
            logger.error(f"License transfer failed: {e}")
            return False
    
    def get_license_usage_stats(self, license_id: str, days: int = 30) -> Dict[str, Any]:
        """Get usage statistics for a license"""
        query = """
            WITH daily_stats AS (
                SELECT 
                    DATE(timestamp) as date,
                    COUNT(*) as validations,
                    COUNT(DISTINCT hardware_id) as unique_devices,
                    COUNT(DISTINCT ip_address) as unique_ips
                FROM license_heartbeats
                WHERE license_id = %s
                    AND timestamp > NOW() - INTERVAL '%s days'
                GROUP BY DATE(timestamp)
            )
            SELECT 
                COUNT(*) as total_days,
                SUM(validations) as total_validations,
                AVG(validations) as avg_daily_validations,
                MAX(unique_devices) as max_devices,
                MAX(unique_ips) as max_ips
            FROM daily_stats
        """
        
        return self.execute_one(query, (license_id, days)) or {}