"""
简单日志模块

格式: 时间 | 级别 | [CLIENT/SERVER] [文件:行号] 消息
- 纯文本格式，无JSON
- 完整打印所有入参出参，不截断
- 日志文件拆分：agent.log（合并）、agent_server.log、agent_client.log
- 使用 contextvars 区分 SERVER/CLIENT 上下文
"""

import logging
import os
import inspect
import contextvars
from typing import Optional, Any
from pathlib import Path


# 全局日志实例
_logger: Optional[logging.Logger] = None

# 使用 ContextVar 替代全局变量，确保 Server/Client 并发时标识正确
_side_var: contextvars.ContextVar[str] = contextvars.ContextVar('log_side', default='UNKNOWN')


def set_log_side(side: str):
    """设置当前上下文的日志标识（SERVER/CLIENT/SYSTEM）"""
    _side_var.set(side)


def get_log_side() -> str:
    """获取当前上下文的日志标识"""
    return _side_var.get()


class PlainFormatter(logging.Formatter):
    """纯文本日志格式化器"""

    def format(self, record: logging.LogRecord) -> str:
        # 时间格式
        time_str = self.formatTime(record, "%Y-%m-%d %H:%M:%S")
        # 级别
        level = record.levelname
        # 消息
        message = record.getMessage()

        return f"{time_str} | {level:<8} | {message}"


class SideStamper(logging.Filter):
    """Logger 级别 filter：为每条日志记录打上 log_side 标记"""

    def filter(self, record):
        record.log_side = _side_var.get()
        return True


class SideFilter(logging.Filter):
    """Handler 级别 filter：只放行指定 side 的记录"""

    def __init__(self, side: str):
        super().__init__()
        self.side = side

    def filter(self, record):
        return getattr(record, 'log_side', '') == self.side


def _get_caller_location(stack_level: int = 3) -> str:
    """获取调用者的代码位置"""
    try:
        frame = inspect.currentframe()
        for _ in range(stack_level):
            if frame is not None:
                frame = frame.f_back

        if frame is not None:
            filename = frame.f_code.co_filename
            lineno = frame.f_lineno

            # 转换为相对路径
            try:
                cwd = os.getcwd()
                if filename.startswith(cwd):
                    filename = filename[len(cwd)+1:]
                elif "/src/" in filename:
                    filename = "src/" + filename.split("/src/")[-1]
            except:
                pass

            return f"{filename}:{lineno}"
    except:
        pass
    return "unknown:0"


def init_logger(
    name: str = "agent",
    log_dir: str = "logs",
    level: int = logging.DEBUG,
) -> logging.Logger:
    """
    初始化日志系统

    Args:
        name: 日志名称
        log_dir: 日志目录
        level: 日志级别

    注意: 仅首次初始化时创建 handler 和清空日志文件，后续调用直接返回
    """
    global _logger

    # 如果已经初始化过，不重复创建 handler
    if _logger is not None and _logger.handlers:
        return _logger

    # 创建日志目录
    log_path = Path(log_dir)
    log_path.mkdir(parents=True, exist_ok=True)

    # 创建 logger
    _logger = logging.getLogger(name)
    _logger.setLevel(level)

    # 关闭并清除旧的 handlers
    for handler in _logger.handlers[:]:
        handler.close()
        _logger.removeHandler(handler)

    # Logger 级别 filter：为每条记录打上 log_side 标记
    _logger.addFilter(SideStamper())

    # 创建 3 个文件 handler
    formatter = PlainFormatter()
    files = {
        "agent.log": None,                      # 合并日志，无 filter
        "agent_server.log": SideFilter("SERVER"),
        "agent_client.log": SideFilter("CLIENT"),
    }

    for filename, side_filter in files.items():
        filepath = log_path / filename
        # 清空日志文件（仅首次启动）
        with open(filepath, "w", encoding="utf-8") as f:
            pass
        fh = logging.FileHandler(filepath, mode="a", encoding="utf-8")
        fh.setLevel(level)
        fh.setFormatter(formatter)
        if side_filter:
            fh.addFilter(side_filter)
        _logger.addHandler(fh)

    # 阻止传播到root logger
    _logger.propagate = False

    return _logger


def get_logger() -> logging.Logger:
    """获取日志实例"""
    global _logger
    if _logger is None:
        _logger = init_logger()
    return _logger


def _format_value(value: Any) -> str:
    """格式化值为字符串，完整展示不截断"""
    if value is None:
        return "None"
    if isinstance(value, str):
        return value
    if isinstance(value, (dict, list)):
        import json
        try:
            return json.dumps(value, ensure_ascii=False, indent=3)
        except:
            return str(value)
    return str(value)


def log_event(event_name: str, **kwargs):
    """
    打印事件日志

    格式: [SIDE] [位置] EVENT: 事件名 | 参数1=值1 | 参数2=值2
    """
    logger = get_logger()
    location = _get_caller_location(3)

    parts = [f"[{_side_var.get()}] [{location}] EVENT: {event_name}"]
    for key, value in kwargs.items():
        parts.append(f"{key}={_format_value(value)}")

    logger.info(" | ".join(parts))


def log_llm_request(provider: str, model: str, request_body: Any):
    """
    打印LLM请求日志 - 完整请求体

    Args:
        provider: 提供商
        model: 模型名称
        request_body: 完整请求参数字典
    """
    logger = get_logger()
    location = _get_caller_location(3)
    import json
    try:
        body_str = json.dumps(request_body, ensure_ascii=False, indent=3)
    except (TypeError, ValueError):
        body_str = str(request_body)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== LLM REQUEST ==========",
        f"provider: {provider}",
        f"model: {model}",
        body_str,
        "========== LLM REQUEST END ==========",
    ]
    logger.info("\n".join(lines))


def log_llm_response(provider: str, model: str, response_body: Any):
    """
    打印LLM响应日志 - 完整响应体

    Args:
        provider: 提供商
        model: 模型名称
        response_body: 完整响应数据字典
    """
    logger = get_logger()
    location = _get_caller_location(3)
    import json
    try:
        body_str = json.dumps(response_body, ensure_ascii=False, indent=3)
    except (TypeError, ValueError):
        body_str = str(response_body)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== LLM RESPONSE ==========",
        f"provider: {provider}",
        f"model: {model}",
        body_str,
        "========== LLM RESPONSE END ==========",
    ]
    logger.info("\n".join(lines))


def log_token_usage(provider: str, model: str, input_tokens: int, output_tokens: int, **kwargs):
    """
    打印 Token 使用量日志

    Args:
        provider: 提供商 (openai/anthropic)
        model: 模型名称
        input_tokens: 输入 token 数
        output_tokens: 输出 token 数
        **kwargs: 其他参数 (如 total_tokens, cached_tokens 等)
    """

    logger = get_logger()
    location = _get_caller_location(3)

    # 计算 total_tokens（含缓存）
    cache_creation = kwargs.get("cache_creation_input_tokens", 0) or 0
    cache_read = kwargs.get("cache_read_input_tokens", 0) or 0
    context = input_tokens + cache_creation + cache_read
    total = kwargs.get("total_tokens", context + output_tokens)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== TOKEN USAGE ==========",
        f"provider: {provider}",
        f"model: {model}",
        f"input_tokens: {input_tokens}",
        f"output_tokens: {output_tokens}",
        f"total_tokens: {total}",
    ]

    # 添加其他可选参数
    for key, value in kwargs.items():
        if key != "total_tokens":  # 已经打印过了
            lines.append(f"{key}: {_format_value(value)}")

    lines.append("========== TOKEN USAGE END ==========")

    logger.info("\n".join(lines))


def log_tool_call(tool_name: str, tool_input: Any, **kwargs):
    """
    打印Tool调用日志 - 完整入参
    """
    logger = get_logger()
    location = _get_caller_location(3)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== TOOL CALL START ==========",
        f"tool_name: {tool_name}",
        f"tool_input: {_format_value(tool_input)}",
    ]

    for key, value in kwargs.items():
        lines.append(f"{key}: {_format_value(value)}")

    lines.append("========== TOOL CALL END ==========")

    logger.info("\n".join(lines))


def log_tool_result(tool_name: str, result: Any, **kwargs):
    """
    打印Tool结果日志 - 完整出参
    """
    logger = get_logger()
    location = _get_caller_location(3)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== TOOL RESULT START ==========",
        f"tool_name: {tool_name}",
        f"result: {_format_value(result)}",
    ]

    for key, value in kwargs.items():
        lines.append(f"{key}: {_format_value(value)}")

    lines.append("========== TOOL RESULT END ==========")

    logger.info("\n".join(lines))


def log_permission_check(action: str, tool_name: str, **kwargs):
    """
    打印权限检查日志 - 入参
    """
    logger = get_logger()
    location = _get_caller_location(3)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== PERMISSION CHECK START ==========",
        f"action: {action}",
        f"tool_name: {tool_name}",
    ]

    for key, value in kwargs.items():
        lines.append(f"{key}: {_format_value(value)}")

    lines.append("========== PERMISSION CHECK END ==========")

    logger.info("\n".join(lines))


def log_permission_result(action: str, tool_name: str, allowed: bool, **kwargs):
    """
    打印权限检查结果日志 - 出参
    """
    logger = get_logger()
    location = _get_caller_location(3)

    lines = [
        f"[{_side_var.get()}] [{location}] ========== PERMISSION RESULT START ==========",
        f"action: {action}",
        f"tool_name: {tool_name}",
        f"allowed: {allowed}",
    ]

    for key, value in kwargs.items():
        lines.append(f"{key}: {_format_value(value)}")

    lines.append("========== PERMISSION RESULT END ==========")

    logger.info("\n".join(lines))


def log_info(message: str, **kwargs):
    """打印INFO级别日志"""
    logger = get_logger()
    location = _get_caller_location(3)

    if kwargs:
        parts = [f"[{_side_var.get()}] [{location}] {message}"]
        for key, value in kwargs.items():
            parts.append(f"{key}={_format_value(value)}")
        logger.info(" | ".join(parts))
    else:
        logger.info(f"[{_side_var.get()}] [{location}] {message}")


def log_debug(message: str, **kwargs):
    """打印DEBUG级别日志"""
    logger = get_logger()
    location = _get_caller_location(3)

    if kwargs:
        parts = [f"[{_side_var.get()}] [{location}] {message}"]
        for key, value in kwargs.items():
            parts.append(f"{key}={_format_value(value)}")
        logger.debug(" | ".join(parts))
    else:
        logger.debug(f"[{_side_var.get()}] [{location}] {message}")


def log_warning(message: str, **kwargs):
    """打印WARNING级别日志"""
    logger = get_logger()
    location = _get_caller_location(3)

    if kwargs:
        parts = [f"[{_side_var.get()}] [{location}] {message}"]
        for key, value in kwargs.items():
            parts.append(f"{key}={_format_value(value)}")
        logger.warning(" | ".join(parts))
    else:
        logger.warning(f"[{_side_var.get()}] [{location}] {message}")


def log_error(message: str, **kwargs):
    """打印ERROR级别日志"""
    logger = get_logger()
    location = _get_caller_location(3)

    if kwargs:
        parts = [f"[{_side_var.get()}] [{location}] {message}"]
        for key, value in kwargs.items():
            parts.append(f"{key}={_format_value(value)}")
        logger.error(" | ".join(parts))
    else:
        logger.error(f"[{_side_var.get()}] [{location}] {message}")
