"""
FastAPI용 로깅 모듈

Django 로거 구조를 참고하여 FastAPI에 최적화된 로깅 시스템.

사용 예시:
    from app.utils.logger import get_logger

    logger = get_logger("song")
    logger.info("노래 생성 완료")
    logger.error("오류 발생", exc_info=True)

로그 레벨:
    1. DEBUG: 디버깅 목적
    2. INFO: 일반 정보
    3. WARNING: 경고 정보 (작은 문제)
    4. ERROR: 오류 정보 (큰 문제)
    5. CRITICAL: 아주 심각한 문제
"""

import logging
import sys
from datetime import datetime
from functools import lru_cache
from logging.handlers import RotatingFileHandler
from typing import Literal

from config import log_settings

# 로그 디렉토리 설정 (config.py의 LogSettings에서 관리)
LOG_DIR = log_settings.get_log_dir()

# 로그 레벨 타입
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]


class LoggerConfig:
    """로거 설정 클래스 (config.py의 LogSettings 참조)"""

    # 출력 대상 설정 (LogSettings에서 가져옴)
    CONSOLE_ENABLED: bool = log_settings.LOG_CONSOLE_ENABLED
    FILE_ENABLED: bool = log_settings.LOG_FILE_ENABLED

    # 기본 설정 (LogSettings에서 가져옴)
    DEFAULT_LEVEL: str = log_settings.LOG_LEVEL
    CONSOLE_LEVEL: str = log_settings.LOG_CONSOLE_LEVEL
    FILE_LEVEL: str = log_settings.LOG_FILE_LEVEL
    MAX_BYTES: int = log_settings.LOG_MAX_SIZE_MB * 1024 * 1024
    BACKUP_COUNT: int = log_settings.LOG_BACKUP_COUNT
    ENCODING: str = "utf-8"

    # 포맷 설정 (LogSettings에서 가져옴)
    CONSOLE_FORMAT: str = log_settings.LOG_CONSOLE_FORMAT
    FILE_FORMAT: str = log_settings.LOG_FILE_FORMAT
    DATE_FORMAT: str = log_settings.LOG_DATE_FORMAT


def _create_console_handler() -> logging.StreamHandler:
    """콘솔 핸들러 생성"""
    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(getattr(logging, LoggerConfig.CONSOLE_LEVEL))
    formatter = logging.Formatter(
        fmt=LoggerConfig.CONSOLE_FORMAT,
        datefmt=LoggerConfig.DATE_FORMAT,
        style="{",
    )
    handler.setFormatter(formatter)
    return handler


# =============================================================================
# 공유 파일 핸들러 (싱글톤)
# 모든 로거가 동일한 파일 핸들러를 공유하여 하나의 로그 파일에 기록
# =============================================================================
_shared_file_handler: RotatingFileHandler | None = None
_shared_error_handler: RotatingFileHandler | None = None


def _get_shared_file_handler() -> RotatingFileHandler:
    """
    공유 파일 핸들러 반환 (싱글톤)

    모든 로거가 하나의 기본 로그 파일(app.log)에 기록합니다.
    파일명: logs/{날짜}_app.log
    """
    global _shared_file_handler

    if _shared_file_handler is None:
        today = datetime.today().strftime("%Y-%m-%d")
        log_file = LOG_DIR / f"{today}_app.log"

        _shared_file_handler = RotatingFileHandler(
            filename=log_file,
            maxBytes=LoggerConfig.MAX_BYTES,
            backupCount=LoggerConfig.BACKUP_COUNT,
            encoding=LoggerConfig.ENCODING,
        )
        _shared_file_handler.setLevel(getattr(logging, LoggerConfig.FILE_LEVEL))
        formatter = logging.Formatter(
            fmt=LoggerConfig.FILE_FORMAT,
            datefmt=LoggerConfig.DATE_FORMAT,
            style="{",
        )
        _shared_file_handler.setFormatter(formatter)

    return _shared_file_handler


def _get_shared_error_handler() -> RotatingFileHandler:
    """
    공유 에러 파일 핸들러 반환 (싱글톤)

    모든 로거의 ERROR 이상 로그가 하나의 에러 로그 파일(error.log)에 기록됩니다.
    파일명: logs/{날짜}_error.log
    """
    global _shared_error_handler

    if _shared_error_handler is None:
        today = datetime.today().strftime("%Y-%m-%d")
        log_file = LOG_DIR / f"{today}_error.log"

        _shared_error_handler = RotatingFileHandler(
            filename=log_file,
            maxBytes=LoggerConfig.MAX_BYTES,
            backupCount=LoggerConfig.BACKUP_COUNT,
            encoding=LoggerConfig.ENCODING,
        )
        _shared_error_handler.setLevel(logging.ERROR)
        formatter = logging.Formatter(
            fmt=LoggerConfig.FILE_FORMAT,
            datefmt=LoggerConfig.DATE_FORMAT,
            style="{",
        )
        _shared_error_handler.setFormatter(formatter)

    return _shared_error_handler


@lru_cache(maxsize=32)
def get_logger(name: str = "app") -> logging.Logger:
    """
    로거 인스턴스 반환 (캐싱 적용)

    Args:
        name: 로거 이름 (모듈명 권장: "song", "lyric", "video" 등)

    Returns:
        설정된 로거 인스턴스

    Example:
        logger = get_logger("song")
        logger.info("노래 처리 시작")
    """
    logger = logging.getLogger(name)

    # 이미 핸들러가 설정된 경우 반환
    if logger.handlers:
        return logger

    # 로그 레벨 설정
    logger.setLevel(getattr(logging, LoggerConfig.DEFAULT_LEVEL))

    # 핸들러 추가 (설정에 따라 선택적으로 추가)
    if LoggerConfig.CONSOLE_ENABLED:
        logger.addHandler(_create_console_handler())

    if LoggerConfig.FILE_ENABLED:
        logger.addHandler(_get_shared_file_handler())
        logger.addHandler(_get_shared_error_handler())

    # 상위 로거로 전파 방지 (중복 출력 방지)
    logger.propagate = False

    return logger


def setup_uvicorn_logging() -> dict:
    """
    Uvicorn 서버의 로깅 설정을 반환합니다.

    ============================================================
    언제 사용하는가?
    ============================================================
    Uvicorn 서버를 Python 코드로 직접 실행할 때 사용합니다.
    CLI 명령어(uvicorn main:app --reload)로 실행할 때는 적용되지 않습니다.

    ============================================================
    사용 방법
    ============================================================
    1. Python 코드에서 uvicorn.run() 호출 시:

        # run.py 또는 main.py 하단
        import uvicorn
        from app.utils.logger import setup_uvicorn_logging

        if __name__ == "__main__":
            uvicorn.run(
                "main:app",
                host="0.0.0.0",
                port=8000,
                reload=True,
                log_config=setup_uvicorn_logging(),  # 여기서 적용
            )

    2. 실행:
        python run.py
        또는
        python main.py

    ============================================================
    어떤 동작을 하는가?
    ============================================================
    Uvicorn의 기본 로깅 형식을 애플리케이션의 LogSettings와 일치시킵니다.

    - formatters: 로그 출력 형식 정의
        - default: 일반 로그용 (서버 시작/종료, 에러 등)
        - access: HTTP 요청 로그용 (클라이언트 IP, 요청 경로, 상태 코드)

    - handlers: 로그 출력 대상 설정
        - stdout으로 콘솔에 출력

    - loggers: Uvicorn 내부 로거 설정
        - uvicorn: 메인 로거
        - uvicorn.error: 에러/시작/종료 로그
        - uvicorn.access: HTTP 요청 로그

    ============================================================
    출력 예시
    ============================================================
    적용 전 (Uvicorn 기본):
        INFO:     127.0.0.1:52341 - "GET /docs HTTP/1.1" 200 OK
        INFO:     Uvicorn running on http://0.0.0.0:8000

    적용 후:
        [2026-01-14 15:30:00] INFO     [uvicorn.access] 127.0.0.1 - "GET /docs HTTP/1.1" 200
        [2026-01-14 15:30:00] INFO     [uvicorn:startup:45] Uvicorn running on http://0.0.0.0:8000

    ============================================================
    반환값 구조 (Python logging.config.dictConfig 형식)
    ============================================================
    {
        "version": 1,                      # dictConfig 버전 (항상 1)
        "disable_existing_loggers": False, # 기존 로거 유지
        "formatters": { ... },             # 포맷터 정의
        "handlers": { ... },               # 핸들러 정의
        "loggers": { ... },                # 로거 정의
    }

    Returns:
        dict: Uvicorn log_config 파라미터에 전달할 설정 딕셔너리
    """
    return {
        # --------------------------------------------------------
        # dictConfig 버전 (필수, 항상 1)
        # --------------------------------------------------------
        "version": 1,

        # --------------------------------------------------------
        # 기존 로거 비활성화 여부
        # False: 기존 로거 유지 (권장)
        # True: 기존 로거 모두 비활성화
        # --------------------------------------------------------
        "disable_existing_loggers": False,

        # --------------------------------------------------------
        # 포맷터 정의
        # 로그 메시지의 출력 형식을 지정합니다.
        # --------------------------------------------------------
        "formatters": {
            # 일반 로그용 포맷터 (서버 시작/종료, 에러 등)
            "default": {
                "format": LoggerConfig.CONSOLE_FORMAT,
                "datefmt": LoggerConfig.DATE_FORMAT,
                "style": "{",  # {변수명} 스타일 사용
            },
            # HTTP 요청 로그용 포맷터
            # 사용 가능한 변수: client_addr, request_line, status_code
            "access": {
                "format": "[{asctime}] {levelname:8} [{name}] {client_addr} - \"{request_line}\" {status_code}",
                "datefmt": LoggerConfig.DATE_FORMAT,
                "style": "{",
            },
        },

        # --------------------------------------------------------
        # 핸들러 정의
        # 로그를 어디에 출력할지 지정합니다.
        # --------------------------------------------------------
        "handlers": {
            # 일반 로그 핸들러 (stdout 출력)
            "default": {
                "formatter": "default",
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
            },
            # HTTP 요청 로그 핸들러 (stdout 출력)
            "access": {
                "formatter": "access",
                "class": "logging.StreamHandler",
                "stream": "ext://sys.stdout",
            },
        },

        # --------------------------------------------------------
        # 로거 정의
        # Uvicorn 내부에서 사용하는 로거들을 설정합니다.
        # --------------------------------------------------------
        "loggers": {
            # Uvicorn 메인 로거
            "uvicorn": {
                "handlers": ["default"],
                "level": "INFO",
                "propagate": False,  # 상위 로거로 전파 방지
            },
            # 에러/시작/종료 로그
            "uvicorn.error": {
                "handlers": ["default"],
                "level": "INFO",
                "propagate": False,
            },
            # HTTP 요청 로그 (GET /path HTTP/1.1 200 등)
            "uvicorn.access": {
                "handlers": ["access"],
                "level": "INFO",
                "propagate": False,
            },
        },
    }


# 편의를 위한 사전 정의된 로거 이름 상수
HOME_LOGGER = "home"
LYRIC_LOGGER = "lyric"
SONG_LOGGER = "song"
VIDEO_LOGGER = "video"
CELERY_LOGGER = "celery"
APP_LOGGER = "app"
