import logging
import json
import datetime
import os
import sys
from typing import Optional

from src.config import LOG_LEVEL
from src.enums import RBDEnum


LOG_FORMAT_DEBUG = "%(levelname)s:%(message)s:%(pathname)s:%(funcName)s:%(lineno)d"

# ANSI Color Codes
RESET = "\033[0m"
COLORS = {
    "DEBUG": "\033[36m",    # Cyan
    "INFO": "\033[32m",     # Green
    "WARNING": "\033[33m",  # Yellow
    "WARN": "\033[33m",     # Yellow
    "ERROR": "\033[31m",    # Red
    "CRITICAL": "\033[1;31m", # Bold Red
}


class LogLevels(RBDEnum):
    info = "INFO"
    warn = "WARN"
    error = "ERROR"
    debug = "DEBUG"


class JSONFormatter(logging.Formatter):
    """
    Custom formatter to output logs in JSON format.
    """
    def format(self, record):
        from src.context import get_request_id, get_user_id, get_username, get_role
        
        request_id = None
        user_id = None
        username = None
        role = None

        try:
            request_id = get_request_id()
            user_id = get_user_id()
            username = get_username()
            role = get_role()
        except Exception:
            pass

        # Standard fields from requirements
        log_record = {
            "timestamp": datetime.datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S"),
            "level": record.levelname,
            "message": record.getMessage(),
        }

        # Add Context information if available
        if request_id:
            log_record["request_id"] = request_id

        # Add Error context if available
        if hasattr(record, "error_id"):
            log_record["error_id"] = record.error_id
        elif "error_id" in record.__dict__:
             log_record["error_id"] = record.error_id
        
        if user_id:
            log_record["user_id"] = user_id

        # Add any extra attributes passed to the log call
        standard_attrs = {
            "args", "asctime", "created", "exc_info", "exc_text", "filename",
            "funcName", "levelname", "levelno", "lineno", "module", "msecs",
            "message", "msg", "name", "pathname", "process", "processName",
            "relativeCreated", "stack_info", "thread", "threadName", "error_id"
        }
        for key, value in record.__dict__.items():
            if key not in standard_attrs and not key.startswith("_"):
                log_record[key] = value
                
        log_json = json.dumps(log_record)

        # Apply color if the output is a terminal
        if sys.stdout.isatty():
            level_color = COLORS.get(record.levelname, "")
            return f"{level_color}{log_json}{RESET}"

        return log_json

def configure_logging():
    log_level = str(LOG_LEVEL).upper()  # cast to string
    log_levels = list(LogLevels)

    if log_level not in log_levels:
        log_level = LogLevels.error

    # Get the root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(log_level)

    # Clear existing handlers to avoid duplicate logs
    if root_logger.hasHandlers():
        root_logger.handlers.clear()

    # Create a stream handler that outputs to stdout
    handler = logging.StreamHandler(sys.stdout)
    
    # Use JSONFormatter for all environments, or could be conditional
    # For now, let's assume the user wants JSON everywhere as requested
    formatter = JSONFormatter()
    
    # If debug mode is specifically requested and we want the old format for debug:
    # if log_level == LogLevels.debug:
    #     formatter = logging.Formatter(LOG_FORMAT_DEBUG)
    
    handler.setFormatter(formatter)
    root_logger.addHandler(handler)

    for logger_name in ["uvicorn", "uvicorn.error", "fastapi"]:
        logger = logging.getLogger(logger_name)
        logger.handlers = []
        logger.propagate = True

    for logger_name in ["uvicorn.access"]:
        logger = logging.getLogger(logger_name)
        logger.handlers = []
        logger.propagate = False

    # # sometimes the slack client can be too verbose
    # logging.getLogger("slack_sdk.web.base_client").setLevel(logging.CRITICAL)

    