"""
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃  Multiprocess-Safe Rotating File Handler                                    ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃  Date    : 2026-02-08                                                        ┃
┃  Summary : Windows 멀티프로세스 환경에서 안전한 로그 파일 회전               ┃
┃            - PermissionError 발생 시 재시도                                  ┃
┃            - 회전 실패 시 현재 파일 계속 사용                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
"""

import os
import time
import logging
from logging.handlers import RotatingFileHandler

# ═══════════════════════════════════════════════════════════════════════════════
# Constants
# ═══════════════════════════════════════════════════════════════════════════════
ROTATION_RETRY_COUNT = 3
ROTATION_RETRY_DELAY = 0.1  # seconds


class SafeRotatingFileHandler(RotatingFileHandler):
    """멀티프로세스 안전한 RotatingFileHandler

    Windows에서 여러 프로세스가 동일한 로그 파일을 사용할 때
    PermissionError를 처리하고 안전하게 회전합니다.

    사용법:
        handler = SafeRotatingFileHandler(
            'app.log',
            maxBytes=10*1024*1024,  # 10MB
            backupCount=5
        )
        logging.getLogger().addHandler(handler)
    """

    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0,
                 encoding=None, delay=False, errors=None):
        super().__init__(filename, mode, maxBytes, backupCount,
                        encoding, delay, errors)
        self._rotation_failed = False

    def doRollover(self):
        """회전 시도, 실패하면 현재 파일 계속 사용"""
        for attempt in range(ROTATION_RETRY_COUNT):
            try:
                super().doRollover()
                self._rotation_failed = False
                return
            except PermissionError:
                if attempt < ROTATION_RETRY_COUNT - 1:
                    time.sleep(ROTATION_RETRY_DELAY)
                else:
                    # 회전 실패 - 현재 파일 계속 사용
                    self._rotation_failed = True
                    self._skip_rotation()

    def _skip_rotation(self):
        """회전 건너뛰기 - 현재 파일 계속 사용"""
        if self.stream:
            self.stream.close()
            self.stream = None
        self.stream = self._open()

    def shouldRollover(self, record):
        """이전 회전 실패 시 일정 시간 동안 회전 시도 안함"""
        if self._rotation_failed:
            # 다음 기회에 다시 시도
            self._rotation_failed = False
            return False
        return super().shouldRollover(record)


class QueueFileHandler(logging.Handler):
    """큐 기반 파일 핸들러 (멀티프로세스 권장)

    모든 프로세스가 큐로 로그를 전송하고,
    단일 리스너가 파일에 기록합니다.

    사용법:
        from multiprocessing import Queue

        log_queue = Queue()

        # 워커 프로세스에서:
        handler = QueueFileHandler(log_queue)
        logging.getLogger().addHandler(handler)

        # 메인 프로세스에서:
        listener = QueueFileListener(log_queue, 'app.log')
        listener.start()
    """

    def __init__(self, queue):
        super().__init__()
        self.queue = queue

    def emit(self, record):
        try:
            # 레코드를 피클 가능하게 변환
            msg = self.format(record)
            self.queue.put_nowait({
                'level': record.levelno,
                'msg': msg,
                'time': record.created
            })
        except Exception:
            self.handleError(record)


class QueueFileListener:
    """큐에서 로그를 받아 파일에 기록하는 리스너

    메인 프로세스에서 단일 인스턴스로 실행합니다.
    """

    def __init__(self, queue, filename, maxBytes=10*1024*1024, backupCount=5):
        self.queue = queue
        self.handler = RotatingFileHandler(
            filename, maxBytes=maxBytes, backupCount=backupCount
        )
        self._stop = False
        self._thread = None

    def start(self):
        """리스너 스레드 시작"""
        import threading
        self._stop = False
        self._thread = threading.Thread(target=self._listen, daemon=True)
        self._thread.start()

    def stop(self):
        """리스너 중지"""
        self._stop = True
        if self._thread:
            self._thread.join(timeout=1.0)

    def _listen(self):
        """큐에서 로그 수신 및 파일 기록"""
        while not self._stop:
            try:
                record = self.queue.get(timeout=0.1)
                if record:
                    self.handler.stream.write(record['msg'] + '\n')
                    self.handler.stream.flush()
            except Exception:
                pass


# ═══════════════════════════════════════════════════════════════════════════════
# Factory Functions
# ═══════════════════════════════════════════════════════════════════════════════
def create_safe_file_handler(filename, maxBytes=10*1024*1024, backupCount=5,
                             encoding='utf-8', fmt=None):
    """안전한 파일 핸들러 생성

    Args:
        filename: 로그 파일 경로
        maxBytes: 최대 파일 크기 (기본 10MB)
        backupCount: 백업 파일 수 (기본 5)
        encoding: 파일 인코딩
        fmt: 로그 포맷 문자열

    Returns:
        SafeRotatingFileHandler 인스턴스
    """
    handler = SafeRotatingFileHandler(
        filename,
        maxBytes=maxBytes,
        backupCount=backupCount,
        encoding=encoding
    )

    if fmt is None:
        fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

    handler.setFormatter(logging.Formatter(fmt))
    return handler


def setup_safe_logging(filename, level=logging.INFO, maxBytes=10*1024*1024,
                       backupCount=5, fmt=None):
    """애플리케이션 로깅을 안전한 핸들러로 설정

    Args:
        filename: 로그 파일 경로
        level: 로깅 레벨
        maxBytes: 최대 파일 크기
        backupCount: 백업 파일 수
        fmt: 로그 포맷 문자열

    Example:
        from py_alaska.task_log_handler import setup_safe_logging
        setup_safe_logging('c:/logs/app.log')
    """
    handler = create_safe_file_handler(filename, maxBytes, backupCount, fmt=fmt)

    root = logging.getLogger()
    root.setLevel(level)

    # 기존 RotatingFileHandler 제거
    for h in root.handlers[:]:
        if isinstance(h, RotatingFileHandler):
            root.removeHandler(h)

    root.addHandler(handler)
    return handler
