import logging
import sys
import time
import functools
import asyncio
import json
import os
from datetime import datetime
from typing import Any, Callable
import traceback

REPORTED_ERRORS_FILE = "data/automated_reports.json"

class KubyLogger:
    def __init__(self, name="KubyBot"):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.DEBUG)
        
        # Créer le format de log
        formatter = logging.Formatter(
            '[%(asctime)s] [%(levelname)s] [%(name)s] [%(funcName)s:%(lineno)d] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        
        # Console handler
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(formatter)
        console_handler.setLevel(logging.DEBUG)
        self.logger.addHandler(console_handler)
        
        # File handler
        file_handler = logging.FileHandler('kuby_logs.log')
        file_handler.setFormatter(formatter)
        file_handler.setLevel(logging.DEBUG)
        self.logger.addHandler(file_handler)
        
        # Error file handler
        error_handler = logging.FileHandler('kuby_errors.log')
        error_handler.setLevel(logging.ERROR)
        error_handler.setFormatter(formatter)
        self.logger.addHandler(error_handler)
        
        # Audit file handler for security events
        audit_handler = logging.FileHandler('kuby_audit.log')
        audit_handler.setLevel(logging.INFO)
        audit_formatter = logging.Formatter(
            '[AUDIT] [%(asctime)s] [%(levelname)s] [%(funcName)s] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        audit_handler.setFormatter(audit_formatter)
        self.logger.addHandler(audit_handler)

        # GitLab handler for automated error reporting
        try:
            from utils.forgejo_client import gitlab_client
            class GitLabHandler(logging.Handler):
                def __init__(self, client):
                    super().__init__()
                    self.client = client
                    self.cooldown = 3600 # 1 hour cooldown per unique error
                    self.last_errors = self._load_reported_errors()

                def _load_reported_errors(self):
                    if os.path.exists(REPORTED_ERRORS_FILE):
                        try:
                            with open(REPORTED_ERRORS_FILE, "r", encoding="utf-8") as f:
                                return json.load(f)
                        except Exception as e:
                            print(f"Error loading reported errors: {e}")
                    return {}

                def _save_reported_errors(self):
                    try:
                        os.makedirs(os.path.dirname(REPORTED_ERRORS_FILE), exist_ok=True)
                        temp_file = f"{REPORTED_ERRORS_FILE}.tmp"
                        with open(temp_file, "w", encoding="utf-8") as f:
                            json.dump(self.last_errors, f, indent=4)
                        os.replace(temp_file, REPORTED_ERRORS_FILE)
                    except Exception as e:
                        print(f"Error saving reported errors: {e}")

                def emit(self, record):
                    if record.levelno >= logging.ERROR:
                        msg = record.getMessage()
                        # Use message + location + simplified traceback for unique key
                        # This key is used for the local cooldown
                        error_key = f"{record.name}.{record.funcName}:{record.lineno} - {msg}"
                        
                        current_time = time.time()
                        last_time = self.last_errors.get(error_key, 0)
                        
                        if current_time - last_time < self.cooldown:
                            return 
                        
                        self.last_errors[error_key] = current_time
                        self._save_reported_errors()
                        
                        # Prepare issue data
                        description = f"**Type:** {record.levelname}\n"
                        description += f"**Message:** {msg}\n"
                        description += f"**Source:** {record.name}.{record.funcName}:{record.lineno}\n\n"
                        if record.exc_info:
                            description += f"**Traceback:**\n```python\n{traceback.format_exc()}\n```"
                        
                        title = f"[AUTO] Error: {msg[:100]}..."
                        labels = ["bug", "auto-report"]
                        
                        # Async reporting flow
                        async def report_flow(client, t, d, l):
                            try:
                                # Check if an open issue with the SAME title already exists on GitLab
                                existing = await client.find_issue_by_title(t, state="opened")
                                if existing:
                                    # If it exists, we don't create a new one to avoid clutter
                                    return
                                
                                # Otherwise, create it
                                await client.create_issue(t, d, l)
                            except Exception as e:
                                print(f"Error in automated reporting flow: {e}")

                        loop = asyncio.get_event_loop()
                        if loop.is_running():
                            loop.create_task(report_flow(self.client, title, description, labels))

            gitlab_handler = GitLabHandler(gitlab_client)
            gitlab_handler.setLevel(logging.ERROR)
            self.logger.addHandler(gitlab_handler)
        except Exception as e:
            self.logger.error(f"Failed to initialize GitLabHandler: {e}")

    def debug(self, message, **kwargs):
        self.logger.debug(message, **kwargs)
    
    def info(self, message, **kwargs):
        self.logger.info(message, **kwargs)
    
    def warning(self, message, **kwargs):
        self.logger.warning(message, **kwargs)
    
    def error(self, message, **kwargs):
        self.logger.error(message, **kwargs)
    
    def critical(self, message, **kwargs):
        self.logger.critical(message, **kwargs)
    
    def audit(self, message, **kwargs):
        """Special audit logging for security events"""
        self.logger.log(25, f"AUDIT: {message}", **kwargs)
    
    def performance(self, message, duration=None, **kwargs):
        """Performance logging with timing information"""
        if duration is not None:
            self.logger.info(f"PERFORMANCE: {message} - Duration: {duration:.3f}s", **kwargs)
        else:
            self.logger.info(f"PERFORMANCE: {message}", **kwargs)

# Performance decorator
def log_performance(func: Callable) -> Callable:
    """Decorator to log function performance"""
    @functools.wraps(func)
    async def async_wrapper(*args, **kwargs):
        start_time = time.time()
        kuby_logger.debug(f"Entering {func.__name__} with args: {args}, kwargs: {kwargs}")
        try:
            result = await func(*args, **kwargs)
            duration = time.time() - start_time
            kuby_logger.performance(f"Completed {func.__name__}", duration=duration)
            return result
        except Exception as e:
            duration = time.time() - start_time
            kuby_logger.error(f"Error in {func.__name__} after {duration:.3f}s: {str(e)}")
            kuby_logger.error(traceback.format_exc())
            raise
    
    @functools.wraps(func)
    def sync_wrapper(*args, **kwargs):
        start_time = time.time()
        kuby_logger.debug(f"Entering {func.__name__} with args: {args}, kwargs: {kwargs}")
        try:
            result = func(*args, **kwargs)
            duration = time.time() - start_time
            kuby_logger.performance(f"Completed {func.__name__}", duration=duration)
            return result
        except Exception as e:
            duration = time.time() - start_time
            kuby_logger.error(f"Error in {func.__name__} after {duration:.3f}s: {str(e)}")
            kuby_logger.error(traceback.format_exc())
            raise
    
    if asyncio.iscoroutinefunction(func):
        return async_wrapper
    return sync_wrapper

# Instance globale du logger
kuby_logger = KubyLogger()
