import logging
import json
from datetime import datetime
from flask import request, current_app, has_app_context

logger = logging.getLogger(__name__)

def log_security_event(event_type, ip_address, user_id=None, username=None, extra_data=None):
    """
    Log security-related events
    
    Args:
        event_type: Type of security event
        ip_address: Client IP address
        user_id: User ID (if applicable)
        username: Username (if applicable)
        extra_data: Additional data to log
    """
    try:
        message = f"Security Event: {event_type}"
        if username:
            message += f" - Username: {username}"
        
        extra_info = {
            'event_type': event_type,
            'ip_address': ip_address,
            'user_agent': request.headers.get('User-Agent', '') if request else '',
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if username:
            extra_info['username'] = username
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Log to database
        if has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level='INFO' if event_type.endswith('_SUCCESS') else 'WARNING',
                    message=message,
                    module='security',
                    user_id=user_id,
                    ip_address=ip_address,
                    user_agent=request.headers.get('User-Agent', '') if request else None,
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log security event to database: {str(db_error)}")
        
        # Also log to application logger
        logger.info(f"{message} - IP: {ip_address}")
        
    except Exception as e:
        logger.error(f"Failed to log security event: {str(e)}")

def log_file_operation(operation_type, filename, user_id=None, match_id=None, upload_id=None, 
                      status='SUCCESS', error_message=None, extra_data=None):
    """
    Log file operations
    
    Args:
        operation_type: Type of file operation
        filename: Name of the file
        user_id: User ID performing operation
        match_id: Associated match ID
        upload_id: Associated upload ID
        status: Operation status
        error_message: Error message if failed
        extra_data: Additional data to log
    """
    try:
        message = f"File Operation: {operation_type} - {filename}"
        if status != 'SUCCESS':
            message += f" - Status: {status}"
        
        extra_info = {
            'operation_type': operation_type,
            'filename': filename,
            'status': status,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if error_message:
            extra_info['error_message'] = error_message
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Determine log level based on status
        log_level = 'INFO' if status == 'SUCCESS' else 'ERROR'
        
        # Log to database
        if has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level=log_level,
                    message=message,
                    module='file_operations',
                    user_id=user_id,
                    match_id=match_id,
                    upload_id=upload_id,
                    ip_address=request.environ.get('HTTP_X_REAL_IP', request.remote_addr) if request else None,
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log file operation to database: {str(db_error)}")
        
        # Also log to application logger
        if status == 'SUCCESS':
            logger.info(message)
        else:
            logger.error(f"{message} - Error: {error_message}")
        
    except Exception as e:
        logger.error(f"Failed to log file operation: {str(e)}")

def log_database_operation(operation_type, table_name, record_id=None, user_id=None, 
                          status='SUCCESS', error_message=None, extra_data=None):
    """
    Log database operations
    
    Args:
        operation_type: Type of database operation (CREATE, UPDATE, DELETE)
        table_name: Name of the table
        record_id: ID of the affected record
        user_id: User ID performing operation
        status: Operation status
        error_message: Error message if failed
        extra_data: Additional data to log
    """
    try:
        message = f"Database Operation: {operation_type} on {table_name}"
        if record_id:
            message += f" (ID: {record_id})"
        
        extra_info = {
            'operation_type': operation_type,
            'table_name': table_name,
            'record_id': record_id,
            'status': status,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if error_message:
            extra_info['error_message'] = error_message
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Determine log level based on status
        log_level = 'INFO' if status == 'SUCCESS' else 'ERROR'
        
        # Log to database (avoid recursion for SystemLog operations)
        if table_name != 'system_logs' and has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level=log_level,
                    message=message,
                    module='database',
                    user_id=user_id,
                    ip_address=request.environ.get('HTTP_X_REAL_IP', request.remote_addr) if request else None,
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log database operation to database: {str(db_error)}")
        
        # Also log to application logger
        if status == 'SUCCESS':
            logger.info(message)
        else:
            logger.error(f"{message} - Error: {error_message}")
        
    except Exception as e:
        logger.error(f"Failed to log database operation: {str(e)}")

def log_api_request(endpoint, method, user_id=None, status_code=200, response_time=None, 
                   error_message=None, extra_data=None):
    """
    Log API requests
    
    Args:
        endpoint: API endpoint
        method: HTTP method
        user_id: User ID making request
        status_code: HTTP status code
        response_time: Response time in milliseconds
        error_message: Error message if failed
        extra_data: Additional data to log
    """
    try:
        message = f"API Request: {method} {endpoint} - Status: {status_code}"
        if response_time:
            message += f" - Time: {response_time}ms"
        
        extra_info = {
            'endpoint': endpoint,
            'method': method,
            'status_code': status_code,
            'response_time': response_time,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if request:
            extra_info.update({
                'ip_address': request.environ.get('HTTP_X_REAL_IP', request.remote_addr),
                'user_agent': request.headers.get('User-Agent', ''),
                'content_length': request.content_length
            })
        
        if error_message:
            extra_info['error_message'] = error_message
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Determine log level based on status code
        if status_code < 400:
            log_level = 'INFO'
        elif status_code < 500:
            log_level = 'WARNING'
        else:
            log_level = 'ERROR'
        
        # Log to database
        if has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level=log_level,
                    message=message,
                    module='api',
                    user_id=user_id,
                    ip_address=request.environ.get('HTTP_X_REAL_IP', request.remote_addr) if request else None,
                    user_agent=request.headers.get('User-Agent', '') if request else None,
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log API request to database: {str(db_error)}")
        
        # Also log to application logger
        if status_code < 400:
            logger.info(message)
        elif status_code < 500:
            logger.warning(message)
        else:
            logger.error(f"{message} - Error: {error_message}")
        
    except Exception as e:
        logger.error(f"Failed to log API request: {str(e)}")

def log_daemon_event(event_type, message, status='INFO', error_message=None, extra_data=None):
    """
    Log daemon-related events
    
    Args:
        event_type: Type of daemon event
        message: Log message
        status: Log level (INFO, WARNING, ERROR)
        error_message: Error message if applicable
        extra_data: Additional data to log
    """
    try:
        full_message = f"Daemon Event: {event_type} - {message}"
        
        extra_info = {
            'event_type': event_type,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if error_message:
            extra_info['error_message'] = error_message
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Only log to database if we have an application context
        if has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level=status,
                    message=full_message,
                    module='daemon',
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log daemon event to database: {str(db_error)}")
        
        # Always log to application logger
        if status == 'INFO':
            logger.info(full_message)
        elif status == 'WARNING':
            logger.warning(full_message)
        else:
            logger.error(f"{full_message} - Error: {error_message}")
        
    except Exception as e:
        logger.error(f"Failed to log daemon event: {str(e)}")

def log_upload_progress(upload_id, progress, status, user_id=None, match_id=None, 
                       error_message=None, extra_data=None):
    """
    Log upload progress events
    
    Args:
        upload_id: Upload ID
        progress: Progress percentage
        status: Upload status
        user_id: User ID performing upload
        match_id: Associated match ID
        error_message: Error message if failed
        extra_data: Additional data to log
    """
    try:
        message = f"Upload Progress: ID {upload_id} - {progress}% - Status: {status}"
        
        extra_info = {
            'upload_id': upload_id,
            'progress': progress,
            'status': status,
            'timestamp': datetime.utcnow().isoformat()
        }
        
        if error_message:
            extra_info['error_message'] = error_message
        
        if extra_data:
            extra_info.update(extra_data)
        
        # Determine log level based on status
        if status in ['completed', 'uploading']:
            log_level = 'INFO'
        elif status == 'failed':
            log_level = 'ERROR'
        else:
            log_level = 'WARNING'
        
        # Log to database
        if has_app_context():
            try:
                from app.models import SystemLog
                SystemLog.log(
                    level=log_level,
                    message=message,
                    module='upload',
                    user_id=user_id,
                    match_id=match_id,
                    upload_id=upload_id,
                    extra_data=extra_info
                )
            except Exception as db_error:
                logger.error(f"Failed to log upload progress to database: {str(db_error)}")
        
        # Also log to application logger (only for significant events to avoid spam)
        if progress % 25 == 0 or status in ['completed', 'failed']:
            if log_level == 'INFO':
                logger.info(message)
            elif log_level == 'WARNING':
                logger.warning(message)
            else:
                logger.error(f"{message} - Error: {error_message}")
        
    except Exception as e:
        logger.error(f"Failed to log upload progress: {str(e)}")

class RequestLogger:
    """Middleware for logging HTTP requests"""
    
    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app):
        """Initialize request logger with Flask app"""
        app.before_request(self.before_request)
        app.after_request(self.after_request)
    
    def before_request(self):
        """Log request start"""
        request.start_time = datetime.utcnow()
    
    def after_request(self, response):
        """Log request completion"""
        try:
            if hasattr(request, 'start_time'):
                response_time = (datetime.utcnow() - request.start_time).total_seconds() * 1000
                
                # Skip logging for static files and health checks
                if not (request.endpoint and 
                       (request.endpoint.startswith('static') or 
                        request.endpoint == 'health_check')):
                    
                    log_api_request(
                        endpoint=request.endpoint or request.path,
                        method=request.method,
                        user_id=getattr(request, 'user_id', None),
                        status_code=response.status_code,
                        response_time=round(response_time, 2)
                    )
        except Exception as e:
            logger.error(f"Request logging error: {str(e)}")
        
        return response

def setup_logging(app):
    """Setup comprehensive logging for the application"""
    # Initialize request logger
    request_logger = RequestLogger(app)
    
    # Configure application logger
    if not app.debug:
        # Production logging
        import logging.handlers
        
        file_handler = logging.handlers.RotatingFileHandler(
            app.config.get('DAEMON_LOG_FILE', 'fixture-daemon.log'),
            maxBytes=10240000,  # 10MB
            backupCount=10
        )
        
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
        app.logger.setLevel(logging.INFO)
        
        # Log application startup
        app.logger.info('Fixture Daemon startup')
    
    return request_logger