"""
Intelligent Logging Middleware for AI SEO Tools

Provides structured logging, file saving, and monitoring capabilities
for all SEO tool operations with performance tracking.
"""

import json
import asyncio
import aiofiles
from datetime import datetime
from functools import wraps
from typing import Dict, Any, Callable
from pathlib import Path
from loguru import logger
import os
import time

# Logging configuration
LOG_BASE_DIR = "logs"
os.makedirs(LOG_BASE_DIR, exist_ok=True)

# Ensure subdirectories exist
for subdir in ["seo_tools", "api_calls", "errors", "performance"]:
    os.makedirs(f"{LOG_BASE_DIR}/{subdir}", exist_ok=True)

class PerformanceLogger:
    """Performance monitoring and logging for SEO operations"""
    
    def __init__(self):
        self.performance_data = {}
    
    async def log_performance(self, operation: str, duration: float, metadata: Dict[str, Any] = None):
        """Log performance metrics for operations"""
        performance_log = {
            "operation": operation,
            "duration_seconds": duration,
            "timestamp": datetime.utcnow().isoformat(),
            "metadata": metadata or {}
        }
        
        await save_to_file(f"{LOG_BASE_DIR}/performance/metrics.jsonl", performance_log)
        
        # Log performance warnings for slow operations
        if duration > 30:  # More than 30 seconds
            logger.warning(f"Slow operation detected: {operation} took {duration:.2f} seconds")
        elif duration > 10:  # More than 10 seconds
            logger.info(f"Operation {operation} took {duration:.2f} seconds")

performance_logger = PerformanceLogger()

async def save_to_file(filepath: str, data: Dict[str, Any]) -> None:
    """
    Asynchronously save structured data to a JSONL file
    
    Args:
        filepath: Path to the log file
        data: Dictionary data to save
    """
    try:
        # Ensure directory exists
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)
        
        # Convert data to JSON string
        json_line = json.dumps(data, default=str) + "\n"
        
        # Write asynchronously
        async with aiofiles.open(filepath, "a", encoding="utf-8") as file:
            await file.write(json_line)
            
    except Exception as e:
        logger.error(f"Failed to save log to {filepath}: {e}")

def log_api_call(func: Callable) -> Callable:
    """
    Decorator for logging API calls with performance tracking
    
    Automatically logs request/response data, timing, and errors
    for SEO tool endpoints.
    """
    @wraps(func)
    async def wrapper(*args, **kwargs):
        start_time = time.time()
        operation_name = func.__name__
        
        # Extract request data
        request_data = {}
        for arg in args:
            if hasattr(arg, 'dict'):  # Pydantic model
                request_data.update(arg.dict())
        
        # Log API call start
        call_log = {
            "operation": operation_name,
            "timestamp": datetime.utcnow().isoformat(),
            "request_data": request_data,
            "status": "started"
        }
        
        logger.info(f"API Call Started: {operation_name}")
        
        try:
            # Execute the function
            result = await func(*args, **kwargs)
            
            execution_time = time.time() - start_time
            
            # Log successful completion
            call_log.update({
                "status": "completed",
                "execution_time": execution_time,
                "success": getattr(result, 'success', True),
                "completion_timestamp": datetime.utcnow().isoformat()
            })
            
            await save_to_file(f"{LOG_BASE_DIR}/api_calls/successful.jsonl", call_log)
            await performance_logger.log_performance(operation_name, execution_time, request_data)
            
            logger.info(f"API Call Completed: {operation_name} in {execution_time:.2f}s")
            
            return result
            
        except Exception as e:
            execution_time = time.time() - start_time
            
            # Log error
            error_log = call_log.copy()
            error_log.update({
                "status": "failed",
                "execution_time": execution_time,
                "error_type": type(e).__name__,
                "error_message": str(e),
                "completion_timestamp": datetime.utcnow().isoformat()
            })
            
            await save_to_file(f"{LOG_BASE_DIR}/api_calls/failed.jsonl", error_log)
            
            logger.error(f"API Call Failed: {operation_name} after {execution_time:.2f}s - {e}")
            
            # Re-raise the exception
            raise
    
    return wrapper

class SEOToolsLogger:
    """Centralized logger for SEO tools with intelligent categorization"""
    
    @staticmethod
    async def log_tool_usage(tool_name: str, input_data: Dict[str, Any], 
                           output_data: Dict[str, Any], success: bool = True):
        """Log SEO tool usage with input/output tracking"""
        usage_log = {
            "tool": tool_name,
            "timestamp": datetime.utcnow().isoformat(),
            "input_data": input_data,
            "output_data": output_data,
            "success": success,
            "input_size": len(str(input_data)),
            "output_size": len(str(output_data))
        }
        
        await save_to_file(f"{LOG_BASE_DIR}/seo_tools/usage.jsonl", usage_log)
    
    @staticmethod
    async def log_ai_analysis(tool_name: str, prompt: str, response: str, 
                            model_used: str, tokens_used: int = None):
        """Log AI analysis operations with token tracking"""
        ai_log = {
            "tool": tool_name,
            "timestamp": datetime.utcnow().isoformat(),
            "model": model_used,
            "prompt_length": len(prompt),
            "response_length": len(response),
            "tokens_used": tokens_used,
            "prompt_preview": prompt[:200] + "..." if len(prompt) > 200 else prompt,
            "response_preview": response[:200] + "..." if len(response) > 200 else response
        }
        
        await save_to_file(f"{LOG_BASE_DIR}/seo_tools/ai_analysis.jsonl", ai_log)
    
    @staticmethod
    async def log_external_api_call(api_name: str, endpoint: str, response_code: int,
                                  response_time: float, request_data: Dict[str, Any] = None):
        """Log external API calls (PageSpeed, etc.)"""
        api_log = {
            "api": api_name,
            "endpoint": endpoint,
            "response_code": response_code,
            "response_time": response_time,
            "timestamp": datetime.utcnow().isoformat(),
            "request_data": request_data or {},
            "success": 200 <= response_code < 300
        }
        
        await save_to_file(f"{LOG_BASE_DIR}/seo_tools/external_apis.jsonl", api_log)
    
    @staticmethod
    async def log_crawling_operation(url: str, pages_crawled: int, errors_found: int,
                                   crawl_depth: int, duration: float):
        """Log web crawling operations"""
        crawl_log = {
            "url": url,
            "pages_crawled": pages_crawled,
            "errors_found": errors_found,
            "crawl_depth": crawl_depth,
            "duration": duration,
            "timestamp": datetime.utcnow().isoformat(),
            "pages_per_second": pages_crawled / duration if duration > 0 else 0
        }
        
        await save_to_file(f"{LOG_BASE_DIR}/seo_tools/crawling.jsonl", crawl_log)

class LogAnalyzer:
    """Analyze logs to provide insights and monitoring"""
    
    @staticmethod
    async def get_performance_summary(hours: int = 24) -> Dict[str, Any]:
        """Get performance summary for the last N hours"""
        try:
            performance_file = f"{LOG_BASE_DIR}/performance/metrics.jsonl"
            if not os.path.exists(performance_file):
                return {"error": "No performance data available"}
            
            # Read recent performance data
            cutoff_time = datetime.utcnow().timestamp() - (hours * 3600)
            operations = []
            
            async with aiofiles.open(performance_file, "r") as file:
                async for line in file:
                    try:
                        data = json.loads(line.strip())
                        log_time = datetime.fromisoformat(data["timestamp"]).timestamp()
                        if log_time >= cutoff_time:
                            operations.append(data)
                    except (json.JSONDecodeError, KeyError):
                        continue
            
            if not operations:
                return {"message": f"No operations in the last {hours} hours"}
            
            # Calculate statistics
            durations = [op["duration_seconds"] for op in operations]
            operation_counts = {}
            for op in operations:
                op_name = op["operation"]
                operation_counts[op_name] = operation_counts.get(op_name, 0) + 1
            
            return {
                "total_operations": len(operations),
                "average_duration": sum(durations) / len(durations),
                "max_duration": max(durations),
                "min_duration": min(durations),
                "operations_by_type": operation_counts,
                "time_period_hours": hours
            }
            
        except Exception as e:
            logger.error(f"Error analyzing performance logs: {e}")
            return {"error": str(e)}
    
    @staticmethod
    async def get_error_summary(hours: int = 24) -> Dict[str, Any]:
        """Get error summary for the last N hours"""
        try:
            error_file = f"{LOG_BASE_DIR}/seo_tools/errors.jsonl"
            if not os.path.exists(error_file):
                return {"message": "No errors recorded"}
            
            cutoff_time = datetime.utcnow().timestamp() - (hours * 3600)
            errors = []
            
            async with aiofiles.open(error_file, "r") as file:
                async for line in file:
                    try:
                        data = json.loads(line.strip())
                        log_time = datetime.fromisoformat(data["timestamp"]).timestamp()
                        if log_time >= cutoff_time:
                            errors.append(data)
                    except (json.JSONDecodeError, KeyError):
                        continue
            
            if not errors:
                return {"message": f"No errors in the last {hours} hours"}
            
            # Analyze errors
            error_types = {}
            functions_with_errors = {}
            
            for error in errors:
                error_type = error.get("error_type", "Unknown")
                function = error.get("function", "Unknown")
                
                error_types[error_type] = error_types.get(error_type, 0) + 1
                functions_with_errors[function] = functions_with_errors.get(function, 0) + 1
            
            return {
                "total_errors": len(errors),
                "error_types": error_types,
                "functions_with_errors": functions_with_errors,
                "recent_errors": errors[-5:],  # Last 5 errors
                "time_period_hours": hours
            }
            
        except Exception as e:
            logger.error(f"Error analyzing error logs: {e}")
            return {"error": str(e)}

# Initialize global logger instance
seo_logger = SEOToolsLogger()
log_analyzer = LogAnalyzer()

# Configure loguru for structured logging
# Commented out to prevent conflicts with main logging configuration
# logger.add(
#     f"{LOG_BASE_DIR}/application.log",
#     rotation="1 day",
#     retention="30 days",
#     level="INFO",
#     format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} | {message}",
#     serialize=True
# )

# logger.add(
#     f"{LOG_BASE_DIR}/errors.log",
#     rotation="1 day",
#     retention="30 days",
#     level="ERROR",
#     format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} | {message}",
#     serialize=True
# )

logger.info("Logging middleware initialized successfully")