"""
audit_logger.py — 서브에이전트 파일 조작 감사 로거

audit-trail.jsonl에 파일 조작 이벤트를 JSONL 포맷으로 기록한다.
fcntl 파일 락으로 동시 쓰기 안전을 보장한다.
"""

import fcntl
import json
import os
from datetime import datetime, timezone
from typing import Optional

DEFAULT_AUDIT_PATH = "/home/jay/workspace/memory/logs/audit-trail.jsonl"


def _validate_str(name: str, value: object) -> str:
    """문자열 인자 유효성 검사 — 비어 있거나 None이면 ValueError."""
    if value is None:
        raise ValueError(f"{name} must not be None")
    if not isinstance(value, str):
        raise TypeError(f"{name} must be a str, got {type(value).__name__}")
    if not value.strip():
        raise ValueError(f"{name} must not be empty")
    return value


def _make_record(
    task_id: str,
    filepath: str,
    tool: str,
    operation: str,
) -> dict:
    """감사 레코드 딕셔너리 생성."""
    return {
        "task_id": task_id,
        "file": filepath,
        "tool": tool,
        "operation": operation,
        "ts": datetime.now(tz=timezone.utc).isoformat().replace("+00:00", "Z"),
        "agent": "subagent",
    }


def _append_record(record: dict, audit_path: str) -> None:
    """레코드를 JSONL 파일에 fcntl 락으로 안전하게 append."""
    parent = os.path.dirname(audit_path)
    if parent:
        os.makedirs(parent, exist_ok=True)

    line = json.dumps(record, ensure_ascii=False) + "\n"

    with open(audit_path, "a", encoding="utf-8") as fh:
        fcntl.flock(fh.fileno(), fcntl.LOCK_EX)
        try:
            fh.write(line)
            fh.flush()
            os.fsync(fh.fileno())
        finally:
            fcntl.flock(fh.fileno(), fcntl.LOCK_UN)


def log_file_operation(
    task_id: str,
    filepath: str,
    tool: str,
    operation: str = "write",
    *,
    audit_path: Optional[str] = None,
) -> None:
    """
    단일 파일 조작을 audit-trail.jsonl에 기록한다.

    Args:
        task_id:    작업 식별자 (예: "task-856.1")
        filepath:   조작된 파일의 절대/상대 경로
        tool:       사용된 도구 이름 (예: "Write", "Edit")
        operation:  조작 종류 (기본값 "write")
        audit_path: 감사 파일 경로 (기본값: DEFAULT_AUDIT_PATH)

    Raises:
        ValueError: task_id, filepath, tool 중 하나가 빈 문자열인 경우
        TypeError:  인자 타입이 str이 아닌 경우
    """
    task_id = _validate_str("task_id", task_id)
    filepath = _validate_str("filepath", filepath)
    tool = _validate_str("tool", tool)

    record = _make_record(task_id, filepath, tool, operation)
    _append_record(record, audit_path or DEFAULT_AUDIT_PATH)


def log_batch_operations(
    task_id: str,
    filepaths: list[str],
    tool: str,
    operation: str = "write",
    *,
    audit_path: Optional[str] = None,
) -> None:
    """
    여러 파일 조작을 audit-trail.jsonl에 일괄 기록한다.

    빈 목록이 전달되면 아무것도 기록하지 않는다.

    Args:
        task_id:    작업 식별자
        filepaths:  조작된 파일 경로 목록
        tool:       사용된 도구 이름
        operation:  조작 종류 (기본값 "write")
        audit_path: 감사 파일 경로 (기본값: DEFAULT_AUDIT_PATH)

    Raises:
        ValueError: task_id 또는 tool이 빈 문자열인 경우
        TypeError:  인자 타입이 맞지 않는 경우
    """
    task_id = _validate_str("task_id", task_id)
    tool = _validate_str("tool", tool)

    if not filepaths:
        return

    resolved_path = audit_path or DEFAULT_AUDIT_PATH

    for fp in filepaths:
        fp = _validate_str("filepath", fp)
        record = _make_record(task_id, fp, tool, operation)
        _append_record(record, resolved_path)
