xiangqi_tui 0.1.0

Chinese chess (Xiangqi) TUI client with UCI/UCCI engine and opening book support
use std::fs::{OpenOptions, create_dir_all};
use std::io::Write;
use std::path::Path;
use std::sync::{Mutex, OnceLock};

static LOG_LOCK: OnceLock<Mutex<()>> = OnceLock::new();

pub fn debug(message: impl AsRef<str>) {
    if !debug_enabled() {
        return;
    }
    write_log("debug", message.as_ref());
}

/// 仅在 `XIANGQI_TUI_DEBUG=1` 时格式化并写入,供热路径日志使用。
pub fn debug_lazy(build: impl FnOnce() -> String) {
    if !debug_enabled() {
        return;
    }
    write_log("debug", &build());
}

/// 设置环境变量 `XIANGQI_TUI_DEBUG=1` 时写入 `logs/runtime.log`。
pub fn debug_enabled() -> bool {
    static ENABLED: OnceLock<bool> = OnceLock::new();
    *ENABLED.get_or_init(|| {
        std::env::var("XIANGQI_TUI_DEBUG")
            .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
            .unwrap_or(false)
    })
}

pub fn warn(message: impl AsRef<str>) {
    write_log("warn", message.as_ref());
}

pub fn error(message: impl AsRef<str>) {
    write_log("error", message.as_ref());
}

fn write_log(level: &str, message: &str) {
    let lock = LOG_LOCK.get_or_init(|| Mutex::new(()));
    let _guard = lock.lock();
    let _ = create_dir_all("logs");
    let path = Path::new("logs").join("runtime.log");
    if let Ok(mut file) = OpenOptions::new().create(true).append(true).open(path) {
        let _ = writeln!(file, "[{level}] {message}");
    }
}