# tkdebug.py
# print / logging を切り替えられる簡易デバッグ関数（print風API）

from __future__ import annotations

import datetime as _dt
import inspect
import logging
import os
import sys
from typing import Any

# ------------------------------------------------------------
# 設定（教材向けの最小構成）
#   0: 無効
#   1: print出力
#   2: logging出力
# ------------------------------------------------------------
DEBUG_LEVEL = 1
LOG_FILE = "debug.log"

# logging は import 時に設定だけしておく（出力はしない）
logging.basicConfig(
    filename=LOG_FILE,
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)s %(message)s",
    encoding="utf-8",
)


def set_debug(level: int | None = None, log_file: str | None = None) -> None:
    """
    デバッグ出力設定を変更する（発展用）。
    """
    global DEBUG_LEVEL, LOG_FILE

    if level is not None:
        DEBUG_LEVEL = level

    if log_file is not None and log_file != LOG_FILE:
        LOG_FILE = log_file
        # basicConfig は2回目以降効かないため、handlersを差し替える
        root = logging.getLogger()
        for h in list(root.handlers):
            root.removeHandler(h)
            h.close()

        logging.basicConfig(
            filename=LOG_FILE,
            level=logging.DEBUG,
            format="%(asctime)s %(levelname)s %(message)s",
            encoding="utf-8",
        )


def dbg(
    *msgs: Any,
    sep: str = " ",
    end: str = "\n",
    flush: bool = False,
) -> None:
    """
    print風のデバッグ出力関数。

    使い方:
        dbg("x =", x, "y =", y)
        dbg("i=", i, "err=", err, sep="")
    """
    if DEBUG_LEVEL <= 0:
        return

    frame = inspect.currentframe()
    try:
        # dbg() 呼び出し元
        caller = frame.f_back if frame is not None else None

        if caller is not None:
            filename = os.path.basename(caller.f_code.co_filename)
            lineno = caller.f_lineno
        else:
            filename = "?"
            lineno = 0

        now = _dt.datetime.now().strftime("%H:%M:%S")
        body = sep.join(str(m) for m in msgs)
        prefix = f"[{now} {filename}:{lineno}] "
        text = prefix + body

        if DEBUG_LEVEL == 1:
            # print風に end / flush を受ける
            print(text, end=end, flush=flush)
        elif DEBUG_LEVEL >= 2:
            # logging は通常1レコード=1行なので end は吸収しておく
            # （末尾改行だけ除去しておく）
            if end and text.endswith("\n"):
                text = text.rstrip("\n")
            logging.debug(text)
    finally:
        # currentframe 参照の明示解放（循環参照対策）
        del frame


# ------------------------------------------------------------
# 動作確認用（import時には何も出力しない）
# ------------------------------------------------------------
if __name__ == "__main__":
    # 0: off / 1: print / 2: logging
    set_debug(level=1)

    x = 10
    y = 3.14
    dbg("start")
    dbg("x =", x, "y =", y)
    dbg("i=", 5, " j=", 9, sep="")  # print風に sep 指定
    dbg("done", flush=True)

    # logging側の確認
    set_debug(level=2, log_file="debug.log")
    dbg("これは logging に出ます")