#!/usr/bin/env python3
"""
에러 추적 모듈

Usage:
    from utils.error_tracker import track_error, error_context, get_recent_errors

    # 직접 호출
    try:
        ...
    except Exception as e:
        track_error("dispatch", e)

    # context manager
    with error_context("dispatch"):
        risky_operation()

    # CLI
    python3 error_tracker.py --recent 10
"""

import json
import os
import sys
import traceback
from contextlib import contextmanager
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Generator, List, Optional

_WORKSPACE_ROOT = os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace")
ERRORS_FILE = Path(_WORKSPACE_ROOT) / "memory" / "logs" / "errors.jsonl"


def _ensure_errors_dir() -> None:
    """에러 로그 디렉토리 자동 생성"""
    ERRORS_FILE.parent.mkdir(parents=True, exist_ok=True)


def track_error(module: str, error: Exception, tb_str: Optional[str] = None) -> None:
    """
    에러를 기록합니다.

    Args:
        module: 에러가 발생한 모듈 이름
        error: Exception 객체
        tb_str: (선택) 트레이스백 문자열. None이면 자동으로 생성
    """
    try:
        _ensure_errors_dir()

        # 트레이스백 문자열 준비
        if tb_str is None:
            tb_str = traceback.format_exc()

        # 현재 시간 (ISO 형식)
        ts = datetime.now().isoformat()

        # 에러 정보 수집
        error_record = {
            "ts": ts,
            "module": module,
            "error_type": type(error).__name__,
            "message": str(error),
            "traceback": tb_str,
        }

        # JSONL 형식으로 기록 (append 모드)
        with open(ERRORS_FILE, "a", encoding="utf-8") as f:
            f.write(json.dumps(error_record, ensure_ascii=False) + "\n")

    except Exception:
        # 추적이 실패해도 메인 로직은 지속
        pass


def get_recent_errors(n: int = 10) -> List[Dict[str, Any]]:
    """
    최근 n개의 에러 기록을 반환합니다.

    Args:
        n: 반환할 에러 개수 (기본값: 10)

    Returns:
        최근 n개의 에러 기록 리스트
    """
    try:
        if not ERRORS_FILE.exists():
            return []

        errors = []
        with open(ERRORS_FILE, "r", encoding="utf-8") as f:
            for line in f:
                if line.strip():
                    try:
                        errors.append(json.loads(line))
                    except json.JSONDecodeError:
                        # 잘못된 JSON 라인은 건너뛰기
                        pass

        # 최근 n개만 반환 (마지막 항목이 가장 최근)
        return errors[-n:] if errors else []

    except Exception:
        return []


@contextmanager
def error_context(module: str) -> Generator[None, None, None]:
    """
    context manager: with 블록 내 예외를 자동으로 추적합니다.

    Usage:
        with error_context("module_name"):
            risky_operation()
    """
    try:
        yield
    except Exception as e:
        track_error(module, e)
        raise


def main() -> None:
    """CLI 인터페이스"""
    if len(sys.argv) > 1 and sys.argv[1] == "--recent":
        n = int(sys.argv[2]) if len(sys.argv) > 2 else 10
        errors = get_recent_errors(n)

        if not errors:
            print("No errors recorded.")
        else:
            print(f"Recent {len(errors)} errors:\n")
            for i, error in enumerate(errors, 1):
                print(f"[{i}] {error['ts']} | {error['module']} | {error['error_type']}: {error['message']}")
                print(f"    Traceback:\n{error['traceback']}")
                print()


if __name__ == "__main__":
    main()
