# -*- coding: utf-8 -*-
"""Detailed trace log for Claude Proxy Control (apply routes / TUN / channels).

Writes UTF-8 lines to:
  %USERPROFILE%\\.claude-proxy-control\\logs\\cpc-trace.log

Format:
  2026-08-07T03:12:00.123 [tid] LEVEL  STEP  message | key=val key2=val2
"""
from __future__ import annotations

import json
import os
import threading
import traceback
from datetime import datetime
from pathlib import Path
from typing import Any


def _home() -> Path:
    env = os.environ.get("CLAUDE_PROXY_HOME", "").strip()
    if env:
        return Path(env)
    return Path(os.environ.get("USERPROFILE", ".")) / ".claude-proxy-control"


def log_dir() -> Path:
    d = _home() / "logs"
    d.mkdir(parents=True, exist_ok=True)
    return d


def log_path() -> Path:
    return log_dir() / "cpc-trace.log"


_lock = threading.Lock()
_MAX_BYTES = 8 * 1024 * 1024  # 8 MB then rotate


def _rotate_if_needed(path: Path) -> None:
    try:
        if path.is_file() and path.stat().st_size >= _MAX_BYTES:
            bak = path.with_suffix(".log.prev")
            if bak.is_file():
                try:
                    bak.unlink()
                except Exception:
                    pass
            path.replace(bak)
    except Exception:
        pass


def _fmt_val(v: Any) -> str:
    if v is None:
        return ""
    if isinstance(v, (str, int, float, bool)):
        s = str(v).replace("\n", "\\n").replace("\r", "")
        if len(s) > 500:
            s = s[:500] + "…"
        return s
    try:
        s = json.dumps(v, ensure_ascii=False, default=str)
    except Exception:
        s = repr(v)
    s = s.replace("\n", " ").replace("\r", "")
    if len(s) > 800:
        s = s[:800] + "…"
    return s


def clog(step: str, message: str = "", *, level: str = "INFO", **extra: Any) -> None:
    """Append one trace line. Never raises to caller."""
    try:
        path = log_path()
        _rotate_if_needed(path)
        tid = threading.get_ident()
        ts = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
        parts = [f"{ts} [{tid}] {level:<5} {step:<28} {message}".rstrip()]
        if extra:
            kv = " ".join(f"{k}={_fmt_val(v)}" for k, v in extra.items())
            parts.append(" | " + kv)
        line = "".join(parts) + "\n"
        with _lock:
            with path.open("a", encoding="utf-8") as f:
                f.write(line)
    except Exception:
        pass


def clog_exc(step: str, message: str = "", exc: BaseException | None = None) -> None:
    err = exc or Exception("unknown")
    clog(
        step,
        message or str(err),
        level="ERROR",
        exc_type=type(err).__name__,
        exc=str(err),
        tb=(traceback.format_exc() if exc else "")[:2000],
    )


def clog_banner(title: str, **extra: Any) -> None:
    clog("========", f"===== {title} =====", level="INFO", **extra)
